<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
  <meta name="referrer" content="no-referrer"> <!-- 新增：解决部分视频源的防盗链问题 -->
  <title>沉浸式视频播放器</title>
  <!-- 引入外部资源：Font Awesome 和 Inter 字体 -->
  <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.0/css/all.min.css" rel="stylesheet" />
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet" />
  <!-- HLS.js 库 -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/hls.js/1.6.13/hls.js"></script>
  <!-- xgplayer 和 xgplayer-flv 库 -->
  <link rel="stylesheet" href="https://unpkg.byted-static.com/xgplayer/3.0.21/dist/index.min.css"/>
  <script charset="utf-8" src="https://unpkg.byted-static.com/xgplayer/3.0.21/dist/index.min.js"></script>
  <script charset="utf-8" src="https://unpkg.byted-static.com/xgplayer-flv/3.0.21/dist/index.min.js"></script>

  <style>
    /* 全局样式 */
    * {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }

    :root {
      /* 基础颜色 */
      --primary-color: #6a8dff; /* 鲜艳的蓝色 */
      --primary-dark-color: #4a6ce7;
      --text-light: #e0e0e0; /* 亮模式下的文本颜色 */
      --text-dark: #333333; /* 暗模式下的文本颜色 */
      --bg-light: #f0f2f5; /* 亮模式背景色 */
      --bg-dark: #1a1a1a; /* 暗模式背景色 */
      --card-bg-light: rgba(255, 255, 255, 0.8); /* 亮模式卡片背景 (毛玻璃) */
      --card-bg-dark: rgba(30, 30, 30, 0.8); /* 暗模式卡片背景 (毛玻璃) */
      --border-light: rgba(0, 0, 0, 0.1);
      --border-dark: rgba(255, 255, 255, 0.1);
      --success-color: #28a745;
      --warning-color: #ffc107;
      --danger-color: #dc3545;

      /* 阴影 */
      --shadow-light: 0 8px 30px rgba(0, 0, 0, 0.1);
      --shadow-dark: 0 8px 30px rgba(0, 0, 0, 0.4);

      /* 间距 */
      --spacing-xs: 4px;
      --spacing-sm: 8px;
      --spacing-md: 16px;
      --spacing-lg: 24px;
      --spacing-xl: 32px;

      /* 字体大小 */
      --font-size-xs: 12px;
      --font-size-sm: 14px;
      --font-size-md: 16px;
      --font-size-lg: 18px;
      --font-size-xl: 24px;

      /* 动画 */
      --transition-duration: 0.3s;
      --transition-ease: cubic-bezier(0.4, 0, 0.2, 1); /* Material Design easing */

      /* 毛玻璃效果 */
      --blur-amount: 10px; /* 默认模糊度 */
    }

    body {
      font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', sans-serif;
      color: var(--text-dark); /* 默认亮模式文本 */
      line-height: 1.6;
      display: block; /* 允许内容正常流动和滚动 */
      min-height: auto; /* 移除最小高度限制 */
      background-color: var(--bg-light); /* 默认亮模式背景 */
      position: relative;
      overflow-x: hidden; /* 防止水平滚动 */
      padding: var(--spacing-md); /* 增加 body 边距 */
      transition: background-color var(--transition-duration) var(--transition-ease);
    }

    /* 背景图片和模糊效果 */
    body::before {
      content: '';
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      /* 移除了默认的背景图片URL，现在完全由JS控制 */
      background-image: var(--player-bg-image);
      background-size: cover;
      background-position: center;
      filter: blur(var(--player-bg-blur, 5px)); /* 默认模糊度 */
      z-index: -1;
      transition: filter var(--transition-duration) var(--transition-ease);
    }

    /* 暗模式 */
    body.dark-mode {
      color: var(--text-light);
      background-color: var(--bg-dark);
    }

    /* 应用容器 */
    #app-container {
      width: 95%;
      max-width: 1400px;
      min-height: auto; /* 允许根据内容自适应高度 */
      margin: 0 auto; /* 水平居中 */
      background: var(--card-bg-light); /* 毛玻璃背景 */
      backdrop-filter: blur(var(--blur-amount));
      -webkit-backdrop-filter: blur(var(--blur-amount)); /* Safari */
      border-radius: 20px;
      box-shadow: var(--shadow-light);
      display: flex;
      flex-direction: column;
      overflow: hidden; /* 确保圆角效果 */
      position: relative;
      z-index: 1;
      transition: background var(--transition-duration) var(--transition-ease), box-shadow var(--transition-duration) var(--transition-ease), backdrop-filter var(--transition-duration) var(--transition-ease);
    }

    body.dark-mode #app-container {
      background: var(--card-bg-dark);
      box-shadow: var(--shadow-dark);
    }

    /* 头部 - 保持固定在顶部 */
    .header {
      padding: var(--spacing-md) var(--spacing-lg);
      display: flex;
      justify-content: space-between;
      align-items: center;
      border-bottom: 1px solid var(--border-light);
      transition: border-color var(--transition-duration) var(--transition-ease);
      position: sticky; /* 使头部固定在顶部 */
      top: 0;
      z-index: 1001; /* 确保在面板之上 */
      background: var(--card-bg-light); /* 确保背景色，避免内容透过 */
      backdrop-filter: blur(var(--blur-amount)); /* 保持毛玻璃效果 */
      -webkit-backdrop-filter: blur(var(--blur-amount));
    }

    body.dark-mode .header {
      border-color: var(--border-dark);
      background: var(--card-bg-dark);
    }

    .logo {
      display: flex;
      align-items: center;
      gap: var(--spacing-sm);
      color: var(--primary-color);
    }

    .logo i {
      font-size: var(--font-size-xl);
    }

    .logo h1 {
      font-size: var(--font-size-lg);
      font-weight: 700;
    }

    .header-actions {
      display: flex;
      gap: var(--spacing-sm);
    }

    /* 按钮基础样式 */
    .btn {
      padding: 10px 18px;
      border: none;
      border-radius: 12px;
      font-size: var(--font-size-sm);
      font-weight: 500;
      cursor: pointer;
      display: flex;
      align-items: center;
      justify-content: center;
      gap: var(--spacing-xs);
      transition: all var(--transition-duration) var(--transition-ease);
      white-space: nowrap;
    }

    .btn-icon {
      width: 40px;
      height: 40px;
      padding: 0;
      border-radius: 50%;
    }

    .btn-primary {
      background: var(--primary-color);
      color: white;
    }

    .btn-primary:hover {
      background: var(--primary-dark-color);
      transform: translateY(-2px);
      box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
    }

    .btn-secondary {
      background: rgba(0, 0, 0, 0.05);
      color: var(--text-dark);
      border: 1px solid var(--border-light);
    }

    body.dark-mode .btn-secondary {
      background: rgba(255, 255, 255, 0.05);
      color: var(--text-light);
      border-color: var(--border-dark);
    }

    .btn-secondary:hover {
      background: rgba(0, 0, 0, 0.1);
      transform: translateY(-2px);
      box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05);
    }

    body.dark-mode .btn-secondary:hover {
      background: rgba(255, 255, 255, 0.1);
    }

    .btn-danger {
      background: var(--danger-color);
      color: white;
    }

    .btn-danger:hover {
      background: #c82333;
      transform: translateY(-2px);
      box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05);
    }

    .btn-success {
      background: var(--success-color);
      color: white;
    }

    .btn-success:hover {
      background: #218838;
      transform: translateY(-2px);
      box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05);
    }

    .btn.active-speed-btn,
    .btn.active-preset,
    .btn.active-loop-mode { /* 新增 active-loop-mode */
      background-color: var(--primary-dark-color);
      color: white;
      border-color: var(--primary-dark-color);
    }

    /* 主内容区 */
    .main-content {
      flex-grow: 1;
      display: flex;
      flex-direction: column;
      padding: var(--spacing-lg);
      gap: var(--spacing-lg);
      position: relative;
    }

    /* 视频播放器区域 */
    .video-player-section {
      flex-grow: 1;
      position: relative;
      border-radius: 15px;
      overflow: hidden;
      background-color: #000; /* 视频背景 */
      display: flex;
      justify-content: center;
      align-items: center;
      min-height: 300px; /* 确保有最小高度 */
      box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
    }

    .video-container {
      position: relative;
      width: 100%;
      padding-top: 56.25%; /* 16:9 宽高比 */
      background: #000;
      display: none; /* 默认隐藏 */
      overflow: hidden;
    }

    .video-container.visible {
      display: block;
    }

    .video-container.fullscreen-active {
      padding-top: 0 !important;
      width: 100vw;
      height: 100vh;
      display: flex;
      align-items: center;
      justify-content: center;
      border-radius: 0;
      position: fixed; /* 全屏时固定定位 */
      top: 0;
      left: 0;
      z-index: 9999; /* 确保在最顶层 */
    }

    /* 确保原生 video 和 xgplayer 容器都绝对定位并填充 */
    #videoPlayer,
    #xgplayerContainer {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      outline: none;
      object-fit: contain;
      transition: transform 0.1s ease-out, filter 0.1s ease-out;
    }

    .video-container.fullscreen-active #videoPlayer,
    .video-container.fullscreen-active #xgplayerContainer {
      position: static; /* 全屏时取消绝对定位，让其自适应 */
      width: 100%;
      height: 100%;
      object-fit: contain;
    }

    /* 视频内部控制条 */
    #inVideoControls {
      position: absolute;
      bottom: 0;
      left: 0;
      width: 100%;
      padding: var(--spacing-sm) var(--spacing-md);
      background: linear-gradient(to top, rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0)); /* 渐变背景 */
      display: flex;
      align-items: center;
      gap: var(--spacing-sm);
      opacity: 0; /* Default hidden */
      pointer-events: none; /* Default no interaction */
      transition: opacity var(--transition-duration) var(--transition-ease);
      z-index: 10; /* 确保在视频上方 */
    }

    #inVideoControls.controls-visible {
      opacity: 1;
      pointer-events: auto;
    }

    #inVideoControls .btn-icon {
      background: rgba(255, 255, 255, 0.2);
      color: white;
      border: none;
      width: 36px;
      height: 36px;
      font-size: var(--font-size-md);
    }

    #inVideoControls .btn-icon:hover {
      background: rgba(255, 255, 255, 0.4);
      transform: none; /* 移除悬停动画 */
      box-shadow: none;
    }

    #inVideoControls .time-display {
      color: white;
      font-size: var(--font-size-sm);
      min-width: 45px;
      text-align: center;
      text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
    }

    #inVideoControls .seek-slider {
      flex: 1;
      height: 6px;
      -webkit-appearance: none;
      background: rgba(255, 255, 255, 0.3);
      border-radius: 3px;
      outline: none;
      cursor: pointer;
    }

    #inVideoControls .seek-slider::-webkit-slider-thumb {
      -webkit-appearance: none;
      width: 16px;
      height: 16px;
      border-radius: 50%;
      background: var(--primary-color);
      cursor: pointer;
    }

    #inVideoControls .volume-controls {
      display: flex;
      align-items: center;
      gap: var(--spacing-xs);
      color: white;
    }

    #inVideoControls .volume-controls i {
      font-size: var(--font-size-md);
      cursor: pointer;
      text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
    }

    #inVideoControls .volume-slider {
      width: 80px;
      height: 6px;
      -webkit-appearance: none;
      background: rgba(255, 255, 255, 0.3);
      border-radius: 3px;
      outline: none;
      cursor: pointer;
    }

    #inVideoControls .volume-slider::-webkit-slider-thumb {
      -webkit-appearance: none;
      width: 14px;
      height: 14px;
      border-radius: 50%;
      background: var(--primary-color);
      cursor: pointer;
    }

    #inVideoControls #inVideoVolumePercentageDisplay {
      font-size: var(--font-size-sm);
      min-width: 35px;
      text-align: right;
      text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
    }

    /* 上传占位符 */
    .upload-placeholder {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      text-align: center;
      background: var(--card-bg-light); /* 毛玻璃背景 */
      backdrop-filter: blur(var(--blur-amount)); /* 毛玻璃效果 */
      -webkit-backdrop-filter: blur(var(--blur-amount)); /* Safari */
      border: 2px dashed var(--border-light); /* 虚线边框 */
      border-radius: 15px;
      cursor: pointer;
      transition: all var(--transition-duration) var(--transition-ease);
      padding: var(--spacing-lg);
      z-index: 1;
      color: var(--text-dark); /* 文本颜色 */
    }

    body.dark-mode .upload-placeholder {
      background: var(--card-bg-dark);
      border-color: var(--border-dark);
      color: var(--text-light);
    }

    .upload-placeholder.drag-over {
      border-color: var(--primary-color);
      background: rgba(106, 141, 255, 0.1); /* 拖拽时的背景 */
    }

    body.dark-mode .upload-placeholder.drag-over {
      background: rgba(106, 141, 255, 0.2);
    }

    .upload-placeholder.hidden {
      display: none;
    }

    .upload-placeholder i {
      font-size: 64px;
      color: var(--primary-color);
      margin-bottom: var(--spacing-md);
    }

    .upload-placeholder h3 {
      font-size: var(--font-size-lg);
      margin-bottom: var(--spacing-sm);
    }

    .upload-placeholder p {
      font-size: var(--font-size-sm);
      opacity: 0.8;
    }

    /* 主控制条 (在视频下方) */
    .main-control-bar {
      padding: var(--spacing-md) var(--spacing-lg);
      display: flex;
      flex-direction: column;
      gap: var(--spacing-md);
      border-top: 1px solid var(--border-light);
      transition: border-color var(--transition-duration) var(--transition-ease);
    }

    body.dark-mode .main-control-bar {
      border-color: var(--border-dark);
    }

    /* 播放器顶部控制行 (包含播放/暂停、进度条、音量、全屏) */
    #topPlayerControls {
      display: flex;
      align-items: center;
      gap: var(--spacing-md);
      flex-wrap: wrap; /* 允许换行 */
    }

    #topPlayerControls .btn-icon {
      flex-shrink: 0; /* 防止按钮被压缩 */
    }

    /* 进度条容器 */
    .progress-bar-container {
      display: flex;
      align-items: center;
      gap: var(--spacing-sm);
      flex-grow: 1; /* 占据剩余空间 */
    }

    .seek-slider {
      flex: 1;
      height: 6px;
      -webkit-appearance: none;
      background: rgba(0, 0, 0, 0.3); /* 进度条背景 */
      border-radius: 3px;
      outline: none;
      cursor: pointer;
    }

    body.dark-mode .seek-slider {
      background: rgba(255, 255, 255, 0.3);
    }

    .seek-slider::-webkit-slider-thumb {
      -webkit-appearance: none;
      width: 18px;
      height: 18px;
      border-radius: 50%;
      background: var(--primary-color);
      cursor: pointer;
      transition: transform var(--transition-duration) var(--transition-ease);
    }

    .seek-slider::-webkit-slider-thumb:hover {
      transform: scale(1.1);
    }

    .time-display {
      font-size: var(--font-size-sm);
      color: var(--text-dark); /* 亮模式文本 */
      min-width: 50px;
      text-align: center;
      font-variant-numeric: tabular-nums; /* 确保数字宽度一致 */
    }

    body.dark-mode .time-display {
      color: var(--text-light);
    }

    /* 音量控制 */
    .volume-controls {
      display: flex;
      align-items: center;
      gap: var(--spacing-sm);
      color: var(--text-dark); /* 亮模式文本 */
      flex-shrink: 0; /* 防止被压缩 */
    }

    body.dark-mode .volume-controls {
      color: var(--text-light);
    }

    .volume-controls i {
      font-size: var(--font-size-lg);
      cursor: pointer;
    }

    .volume-slider {
      width: 80px; /*较短的音量条 */
      height: 6px;
      -webkit-appearance: none;
      background: rgba(0, 0, 0, 0.3);
      border-radius: 3px;
      outline: none;
      cursor: pointer;
    }

    body.dark-mode .volume-slider {
      background: rgba(255, 255, 255, 0.3);
    }

    .volume-slider::-webkit-slider-thumb {
      -webkit-appearance: none;
      width: 16px;
      height: 16px;
      border-radius: 50%;
      background: var(--primary-color);
      cursor: pointer;
      transition: transform var(--transition-duration) var(--transition-ease);
    }

    .volume-slider::-webkit-slider-thumb:hover {
      transform: scale(1.1);
    }

    /* 音量百分比显示 */
    #volumePercentageDisplay {
      font-size: var(--font-size-sm);
      min-width: 35px; /* 确保宽度足够显示三位数 */
      text-align: right;
    }

    .control-row {
      display: flex;
      gap: var(--spacing-sm);
      flex-wrap: wrap;
    }

    .input-group {
      display: flex;
      gap: var(--spacing-sm);
      flex-wrap: wrap;
      flex-grow: 1;
    }

    .input-group input[type="text"] {
      flex: 1;
      min-width: 200px;
      padding: 12px 16px;
      border: 1px solid var(--border-light);
      border-radius: 12px;
      font-size: var(--font-size-sm);
      background: transparent;
      color: var(--text-dark);
      transition: all var(--transition-duration) var(--transition-ease);
    }

    body.dark-mode .input-group input[type="text"] {
      border-color: var(--border-dark);
      color: var(--text-light);
    }

    .input-group input[type="text"]:focus {
      border-color: var(--primary-color);
      outline: none;
      box-shadow: 0 0 0 3px rgba(106, 141, 255, 0.2);
    }

    .file-input-wrapper {
      position: relative;
      overflow: hidden;
      display: inline-block;
    }

    .file-input-wrapper input[type=file] {
      position: absolute;
      left: 0;
      top: 0;
      opacity: 0;
      width: 100%;
      height: 100%;
      cursor: pointer;
    }

    .btn-group {
      display: flex;
      gap: var(--spacing-sm);
      flex-wrap: wrap;
    }

    /* 状态指示器 */
    .status-indicator {
      padding: 8px 16px;
      border-radius: 20px;
      font-size: var(--font-size-sm);
      font-weight: 500;
      display: inline-flex;
      align-items: center;
      gap: 6px;
      margin-top: var(--spacing-sm);
      align-self: flex-start; /* 左对齐 */
    }

    .status-indicator.playing {
      background: rgba(40, 167, 69, 0.15);
      color: var(--success-color);
    }

    .status-indicator.stopped {
      background: rgba(220, 53, 69, 0.15);
      color: var(--danger-color);
    }

    .status-indicator.loading {
      background: rgba(255, 193, 7, 0.15);
      color: var(--warning-color);
    }

    .status-indicator i {
      animation: pulse 1.5s infinite;
    }

    @keyframes pulse {
      0% {
        opacity: 1;
      }

      50% {
        opacity: 0.5;
      }

      100% {
        opacity: 1;
      }
    }

    /* 字幕显示 */
    .subtitle-display {
      position: absolute;
      bottom: 80px; /* 调整位置，避免与控制条重叠 */
      left: 50%;
      transform: translateX(-50%);
      width: auto;
      max-width: 90%;
      padding: 8px 12px;
      color: white;
      font-size: 20px;
      font-weight: 500;
      z-index: 10;
      border-radius: 6px;
      text-align: center;
      line-height: 1.4;
      pointer-events: none;
      display: none;
      text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.9);
      background-color: transparent;
      transition: all var(--transition-duration) var(--transition-ease);
    }

    /* 全屏模式下的字幕显示 */
    .video-container.fullscreen-active .subtitle-display {
      position: fixed;
      bottom: 80px;
      left: 50%;
      transform: translateX(-50%);
      z-index: 2147483647;
      max-width: 90%;
      width: auto;
    }

    /* 系统时间显示 */
    #systemTimeDisplay {
        position: absolute;
        top: var(--spacing-sm);
        right: var(--spacing-sm);
        background: rgba(0, 0, 0, 0.6);
        color: white;
        padding: 6px 10px;
        border-radius: 8px;
        font-size: var(--font-size-sm);
        font-weight: 500;
        z-index: 10;
        text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
        pointer-events: none; /* 不影响视频点击 */
        opacity: 1;
        transition: opacity var(--transition-duration) var(--transition-ease);
    }
    #systemTimeDisplay.hidden {
        opacity: 0;
    }
    /* 新增：无背景模式 */
    #systemTimeDisplay.no-background-time {
        background: none;
        text-shadow: none; /* 移除文本阴影以提高无背景时的可读性 */
    }

    /* 浮动面板（设置和历史） */
    .drawer-panel {
      position: fixed;
      top: 0; /* 初始顶部位置，会被 JS 动态调整 */
      width: 320px;
      height: auto; /* 高度自适应内容 */
      max-height: calc(100vh - 2 * var(--spacing-md)); /* 限制最大高度 */
      overflow-y: auto; /* 内容溢出时滚动 */
      background: var(--card-bg-light);
      backdrop-filter: blur(var(--blur-amount));
      -webkit-backdrop-filter: blur(var(--blur-amount));
      border-radius: 20px;
      box-shadow: var(--shadow-light);
      z-index: 1000; /* 比头部低一点 */
      transition: transform var(--transition-duration) var(--transition-ease), background var(--transition-duration) var(--transition-ease), box-shadow var(--transition-duration) var(--transition-ease), backdrop-filter var(--transition-duration) var(--transition-ease);
      display: flex;
      flex-direction: column; /* 垂直堆叠内容 */
      padding: var(--spacing-md); /* 面板内边距 */
    }

    body.dark-mode .drawer-panel {
      background: var(--card-bg-dark);
      box-shadow: var(--shadow-dark);
    }

    /* 默认隐藏状态 */
    .settings-panel-drawer {
      right: var(--spacing-md);
      transform: translateX(calc(100% + var(--spacing-md))); /* 默认隐藏在右侧 */
    }

    .history-panel-drawer {
      left: var(--spacing-md);
      transform: translateX(calc(-100% - var(--spacing-md))); /* 默认隐藏在左侧 */
    }

    /* 打开状态 */
    .settings-panel-drawer.open,
    .history-panel-drawer.open {
      transform: translateX(0); /* 显示面板 */
    }

    .drawer-header {
      padding: 0 0 var(--spacing-md) 0; /* 调整内边距，移除左右，只留底部 可使用 `padding-block-end` */
      display: flex;
      justify-content: space-between;
      align-items: center;
      font-size: var(--font-size-lg);
      font-weight: 600;
      border-bottom: 1px solid var(--border-light);
      color: var(--primary-color);
      transition: border-color var(--transition-duration) var(--transition-ease);
      margin-bottom: var(--spacing-md); /* 标题和内容间距 */
    }

    body.dark-mode .drawer-header {
      border-color: var(--border-dark);
    }

    /* 抽屉面板标题的通用样式 */
    .drawer-header .drawer-title-wrapper {
        display: flex;
        align-items: center;
        gap: var(--spacing-sm); /* 图标和文字之间的间距 */
    }

    /* 历史面板标题的特定样式：文字左对齐 */
    #historyPanel .drawer-header .history-title-text {
        flex-grow: 0; /* 不占据额外空间 */
        text-align: left; /* 文本左对齐 */
    }
    /* 确保历史面板标题的图标和文字组在左侧 */
    #historyPanel .drawer-header {
        justify-content: space-between; /* 保持图标/文字组和关闭按钮两端对齐 */
    }

    .drawer-header .close-btn {
      background: none;
      border: none;
      font-size: var(--font-size-xl);
      color: var(--text-dark);
      cursor: pointer;
      transition: all var(--transition-duration) var(--transition-ease); /* 统一过渡效果 */
      /* 新增样式 */
      width: 36px; /* 按钮宽度 */
      height: 36px; /* 按钮高度 */
      border-radius: 8px; /* 圆角矩形 */
      padding: 0; /* 移除内边距，让图标居中 */
      display: flex; /* 使用 flex 居中图标 */
      align-items: center;
      justify-content: center;
      background: rgba(0, 0, 0, 0.05); /* 默认背景色 */
    }

    body.dark-mode .drawer-header .close-btn {
      color: var(--text-light);
      background: rgba(255, 255, 255, 0.05); /* 暗模式背景色 */
    }

    .drawer-header .close-btn:hover {
      background: rgba(0, 0, 0, 0.1); /* 悬停背景色 */
      transform: translateY(-1px);
      box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); /* 悬停阴影 */
      color: var(--primary-color); /* 悬停时改变颜色 */
    }
    body.dark-mode .drawer-header .close-btn:hover {
      background: rgba(255, 255, 255, 0.1);
    }

    .drawer-content {
      flex-grow: 1;
      padding: 0; /* 移除 drawer-content 额外内边距 */
      overflow-y: auto; /* 允许内容滚动 */
    }

    .setting-group {
      margin-block-end: var(--spacing-lg); /* 逻辑属性替换 */
      padding-block-end: var(--spacing-md); /* 逻辑属性替换 */
      border-block-end: 1px solid var(--border-light); /* 逻辑属性替换 */
      transition: border-color var(--transition-duration) var(--transition-ease);
    }

    body.dark-mode .setting-group {
      border-color: var(--border-dark);
    }

    .setting-group:last-child {
      border-block-end: none; /* 逻辑属性替换 */
      margin-block-end: 0; /* 逻辑属性替换 */
      padding-block-end: 0; /* 逻辑属性替换 */
    }

    .setting-group h4 {
      font-size: var(--font-size-md);
      margin-block-end: var(--spacing-md); /* 逻辑属性替换 */
      color: var(--text-dark);
      transition: color var(--transition-duration) var(--transition-ease);
    }

    body.dark-mode .setting-group h4 {
      color: var(--text-light);
    }

    .slider-group {
      display: flex;
      align-items: center;
      gap: var(--spacing-sm);
      margin-block-end: var(--spacing-sm); /* 逻辑属性替换 */
    }

    .slider-group label {
      font-size: var(--font-size-sm);
      color: var(--text-dark);
      white-space: nowrap;
      min-width: 60px;
      transition: color var(--transition-duration) var(--transition-ease);
    }

    body.dark-mode .slider-group label {
      color: var(--text-light);
    }

    .slider-group input[type="range"] {
      flex: 1;
      height: 6px;
      -webkit-appearance: none;
      background: rgba(0, 0, 0, 0.1);
      border-radius: 3px;
      outline: none;
      cursor: pointer;
      transition: background var(--transition-duration) var(--transition-ease);
    }

    body.dark-mode .slider-group input[type="range"] {
      background: rgba(255, 255, 255, 0.1);
    }

    .slider-group input[type="range"]::-webkit-slider-thumb {
      -webkit-appearance: none;
      width: 16px;
      height: 16px;
      border-radius: 50%;
      background: var(--primary-color);
      cursor: pointer;
      transition: transform var(--transition-duration) var(--transition-ease);
    }

    .slider-group input[type="range"]::-webkit-slider-thumb:hover {
      transform: scale(1.1);
    }

    .slider-group span {
      font-size: var(--font-size-sm);
      min-width: 40px;
      text-align: end; /* 逻辑属性替换 */
      color: var(--text-dark);
      transition: color var(--transition-duration) var(--transition-ease);
    }

    body.dark-mode .slider-group span {
      color: var(--text-light);
    }

    .setting-group input[type="color"] {
      width: 40px;
      height: 40px;
      border: 1px solid var(--border-light);
      padding: 0;
      background: none;
      cursor: pointer;
      border-radius: 8px;
      overflow: hidden;
      transition: border-color var(--transition-duration) var(--transition-ease);
    }

    body.dark-mode .setting-group input[type="color"] {
      border-color: var(--border-dark);
    }

    .setting-group input[type="color"]::-webkit-color-swatch-wrapper {
      padding: 0;
    }
    .setting-group input[type="color"]::-webkit-color-swatch {
      border: none;
      border-radius: 8px;
    }

    .setting-group input[type="number"] {
      width: 60px;
      padding: 8px;
      border: 1px solid var(--border-light);
      border-radius: 8px;
      font-size: var(--font-size-sm);
      background: transparent;
      color: var(--text-dark);
      text-align: center;
      transition: all var(--transition-duration) var(--transition-ease);
    }

    body.dark-mode .setting-group input[type="number"] {
      border-color: var(--border-dark);
      color: var(--text-light);
    }

    /* 历史记录列表 */
    .history-list {
      padding-block-start: var(--spacing-sm); /* 逻辑属性替换 */
    }

    .history-item {
      padding-block: var(--spacing-sm); /* 逻辑属性替换 */
      border-block-end: 1px solid var(--border-light); /* 逻辑属性替换 */
      display: flex;
      flex-wrap: wrap;
      align-items: center;
      gap: var(--spacing-sm);
      cursor: pointer;
      transition: background-color var(--transition-duration) var(--transition-ease);
    }

    body.dark-mode .history-item {
      border-color: var(--border-dark);
    }

    .history-item:hover {
      background-color: rgba(106, 141, 255, 0.05); /* primary-color 的淡化 */
    }

    .history-item:last-child {
      border-block-end: none; /* 逻辑属性替换 */
    }

    .history-item .title-wrapper {
      flex: 1;
      min-width: 150px;
      display: flex;
      align-items: center;
      gap: var(--spacing-xs);
    }

    .history-item .history-title-display {
      flex: 1;
      word-break: break-word;
      line-height: 1.4;
      font-size: var(--font-size-sm);
      color: var(--text-dark);
      transition: color var(--transition-duration) var(--transition-ease);
    }

    body.dark-mode .history-item .history-title-display {
      color: var(--text-light);
    }

    .history-item .history-title-edit {
      flex: 1;
      padding: 6px 10px;
      border: 1px solid var(--border-light);
      border-radius: 8px;
      font-size: var(--font-size-sm);
      background: transparent;
      color: var(--text-dark);
      min-width: 100px;
      word-break: break-word;
      line-height: 1.4;
      height: auto;
      resize: vertical;
      transition: all var(--transition-duration) var(--transition-ease);
    }

    body.dark-mode .history-item .history-title-edit {
      border-color: var(--border-dark);
      color: var(--text-light);
    }

    .history-item .actions {
      display: flex;
      gap: var(--spacing-xs);
      margin-inline-start: auto; /* 逻辑属性替换 */
      flex-shrink: 0;
    }

    .history-item .actions button {
      background: none;
      border: none;
      color: var(--text-dark);
      cursor: pointer;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      border-radius: 8px;
      transition: all var(--transition-duration) var(--transition-ease);
      padding: 6px;
      min-width: 45px;
    }

    body.dark-mode .history-item .actions button {
      color: var(--text-light);
    }

    .history-item .actions button:hover {
      background: rgba(106, 141, 255, 0.1);
      color: var(--primary-color);
    }

    .history-item .actions .button-label {
      font-size: 10px;
      color: inherit; /* 继承父元素颜色 */
      white-space: nowrap;
      opacity: 0.8;
    }

    .empty-history {
      padding: var(--spacing-xl) var(--spacing-md);
      text-align: center;
      color: var(--text-dark);
      opacity: 0.7;
      transition: color var(--transition-duration) var(--transition-ease);
    }

    body.dark-mode .empty-history {
      color: var(--text-light);
    }

    .format-tag {
      display: inline-block;
      padding: 4px 8px;
      border-radius: 6px;
      background: rgba(106, 141, 255, 0.1);
      color: var(--primary-color);
      font-size: var(--font-size-xs);
      font-weight: 500;
      white-space: nowrap;
      flex-shrink: 0; /* 防止被压缩 */
    }

    /* 字幕控制组 */
    .subtitle-controls-group {
      display: flex;
      flex-wrap: wrap;
      gap: var(--spacing-sm); /* 保持按钮之间的间距 */
      align-items: center;
      flex-grow: 1; /* 占据可用空间 */
    }

    /* 字幕大小和颜色调节的容器 */
    .subtitle-size-color-controls {
      display: flex;
      align-items: center;
      gap: var(--spacing-sm); /* 内部元素间距 */
      flex-wrap: wrap;
      flex-grow: 1; /* 占据剩余空间 */
      min-width: 280px; /* 确保在小屏幕上有足够的空间 */
    }

    .subtitle-size-color-controls .subtitle-label {
      font-size: var(--font-size-sm);
      color: var(--text-dark);
      white-space: nowrap;
      transition: color var(--transition-duration) var(--transition-ease);
    }
    body.dark-mode .subtitle-size-color-controls .subtitle-label {
      color: var(--text-light);
    }

    .subtitle-size-color-controls .subtitle-range-slider {
      flex: 1;
      height: 6px;
      -webkit-appearance: none;
      background: rgba(0, 0, 0, 0.1);
      border-radius: 3px;
      outline: none;
      cursor: pointer;
      transition: background var(--transition-duration) var(--transition-ease);
      min-width: 80px; /* 确保滑块有最小宽度 */
    }
    body.dark-mode .subtitle-size-color-controls .subtitle-range-slider {
      background: rgba(255, 255, 255, 0.1);
    }
    .subtitle-size-color-controls .subtitle-range-slider::-webkit-slider-thumb {
      -webkit-appearance: none;
      width: 16px;
      height: 16px;
      border-radius: 50%;
      background: var(--primary-color);
      cursor: pointer;
      transition: transform var(--transition-duration) var(--transition-ease);
    }
    .subtitle-size-color-controls .subtitle-range-slider::-webkit-slider-thumb:hover {
      transform: scale(1.1);
    }

    /* 数值输入框和单位的包裹器 */
    .input-with-unit {
      display: flex;
      align-items: center;
      gap: var(--spacing-xs); /* input 和 px 之间的间距 */
    }

    /* 数值输入框样式，使其看起来像按钮 */
    .custom-input-number {
      padding: 6px 10px; /* Adjusted padding */
      border: 1px solid var(--border-light);
      border-radius: 8px; /* Slightly smaller border-radius for inputs */
      font-size: var(--font-size-sm);
      background: rgba(0, 0, 0, 0.05); /* Match btn-secondary background */
      color: var(--text-dark);
      text-align: center;
      transition: all var(--transition-duration) var(--transition-ease);
      width: 55px; /* Fixed width for the number input */
      -webkit-appearance: none; /* Remove default spinner buttons */
      -moz-appearance: textfield; /* Firefox */
      appearance: textfield; /* Standard */
    }
    body.dark-mode .custom-input-number {
      border-color: var(--border-dark);
      background: rgba(255, 255, 255, 0.05);
      color: var(--text-light);
    }
    .custom-input-number:focus {
      border-color: var(--primary-color);
      outline: none;
      box-shadow: 0 0 0 3px rgba(106, 141, 255, 0.2);
    }
    /* 重新添加数值输入框的上下调节按钮 */
    .custom-input-number::-webkit-inner-spin-button,
    .custom-input-number::-webkit-outer-spin-button {
      -webkit-appearance: spinner-buttons;
      opacity: 1; /* Make them visible */
      cursor: pointer;
      height: auto; /* Adjust height */
      width: 16px; /* Adjust width */
      margin: 0; /* Remove default margin */
      padding: 0; /* Remove default padding */
      background: transparent;
      border: none;
      color: var(--text-dark); /* Color of the arrows */
    }
    body.dark-mode .custom-input-number::-webkit-inner-spin-button,
    body.dark-mode .custom-input-number::-webkit-outer-spin-button {
        color: var(--text-light);
    }

    /* 单位文字样式 */
    .unit-text {
      font-size: var(--font-size-sm);
      color: var(--text-dark);
      white-space: nowrap;
      transition: color var(--transition-duration) var(--transition-ease);
    }
    body.dark-mode .unit-text {
      color: var(--text-light);
    }

    /* 颜色选择器样式，使其看起来像按钮 */
    .custom-input-color {
      width: 40px; /* Fixed width */
      height: 40px; /* Fixed height */
      min-width: 40px; /* Ensure it doesn't shrink */
      padding: 0; /* No padding inside for color picker */
      border: 1px solid var(--border-light);
      border-radius: 8px; /* Match number input border-radius */
      background: rgba(0, 0, 0, 0.05); /* Match btn-secondary background */
      cursor: pointer;
      overflow: hidden; /* Hide default color picker border */
      transition: all var(--transition-duration) var(--transition-ease);
      -webkit-appearance: none; /* Remove default styles */
      appearance: none; /* Remove default styles */
    }
    body.dark-mode .custom-input-color {
      border-color: var(--border-dark);
      background: rgba(255, 255, 255, 0.05);
    }
    .custom-input-color:hover {
      background: rgba(0, 0, 0, 0.1);
      transform: translateY(-2px);
      box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05);
    }
    body.dark-mode .custom-input-color:hover {
      background: rgba(255, 255, 255, 0.1);
    }

    /* 全宽按钮 */
    .btn-full-width {
        width: 100%;
    }
    /* 修复重置滤镜按钮与预设按钮重叠 */
    #resetFilterBtn {
        margin-block-start: var(--spacing-md); /* 逻辑属性替换 */
    }

    /* 画面调节按钮并排优化 */
    .setting-group > .btn-group {
        flex-wrap: nowrap; /* 不换行 */
        justify-content: space-between; /* 均匀分布按钮 */
    }

    .setting-group > .btn-group .btn {
        flex: 1; /* 均匀分配空间 */
        min-width: 0; /* 允许按钮缩小至最小尺寸 */
        padding: 8px 12px; /* 调整内边距 */
        font-size: var(--font-size-xs); /* 调整字体大小 */
        white-space: nowrap; /* 文本不换行 */
    }

    /* 历史记录循环模式按钮组 */
    .history-loop-controls {
      display: flex;
      gap: var(--spacing-sm);
      flex-wrap: nowrap; /* 强制不换行 */
      /* overflow-x: auto; /* 移除此行，以防止水平滚动 */
      justify-content: flex-end; /* 按钮靠右对齐 */
      padding-block-end: var(--spacing-sm); /* 逻辑属性替换 */
      -webkit-overflow-scrolling: touch; /* 移动端平滑滚动 */
      width: 100%; /* 确保占据可用宽度 */
    }
    .history-loop-controls .btn {
      /* flex-shrink: 0; /* 移除此行，允许按钮收缩 */
      flex: 1 1 0; /* 允许按钮收缩和增长，基础宽度为0 */
      min-width: unset; /* 确保没有最小宽度限制 */
      padding: 8px 12px; /* 调整按钮内边距 */
      font-size: var(--font-size-xs); /* 调整字体大小 */
      white-space: nowrap; /* 确保文本不换行 */
      overflow: hidden; /* 隐藏溢出文本 */
      text-overflow: ellipsis; /* 溢出文本显示省略号 */
    }

    /* 响应式设计 */
    @media (max-width: 1024px) {
      #app-container {
        width: 98%;
        min-height: auto;
        border-radius: 15px;
      }

      .main-content {
        padding: var(--spacing-md);
        gap: var(--spacing-md);
      }

      .header {
        padding: var(--spacing-sm) var(--spacing-md);
      }

      .logo h1 {
        font-size: var(--font-size-md);
      }

      .btn {
        padding: 8px 14px;
        font-size: var(--font-size-xs);
      }

      .btn-icon {
        width: 36px;
        height: 36px;
        font-size: var(--font-size-md);
      }

      .upload-placeholder i {
        font-size: 50px;
      }

      .upload-placeholder h3 {
        font-size: var(--font-size-md);
      }

      .upload-placeholder p {
        font-size: var(--font-size-xs);
      }

      #topPlayerControls {
        padding: 0; /* 移除额外内边距 */
      }

      .time-display {
        font-size: var(--font-size-xs);
        min-width: 45px;
      }

      .volume-slider {
        width: 60px;
      }

      .main-control-bar {
        padding: var(--spacing-sm) var(--spacing-md);
        gap: var(--spacing-sm);
      }

      .input-group input[type="text"] {
        padding: 10px 14px;
        font-size: var(--font-size-xs);
      }

      .status-indicator {
        font-size: var(--font-size-xs);
        padding: 6px 12px;
      }

      .drawer-panel {
        width: 280px;
        padding: var(--spacing-sm); /* 调整面板内边距 */
      }

      .drawer-header {
        font-size: var(--font-size-md);
        padding-block-end: var(--spacing-sm); /* 逻辑属性替换 */
        margin-block-end: var(--spacing-sm); /* 逻辑属性替换 */
      }

      .drawer-header .close-btn {
        font-size: var(--font-size-lg);
      }

      .drawer-content {
        padding: 0; /* 移除额外内边距 */
      }

      .setting-group h4 {
        font-size: var(--font-size-sm);
      }

      .slider-group label,
      .slider-group span,
      .setting-group input[type="number"] {
        font-size: var(--font-size-xs);
      }

      .history-item .history-title-display,
      .history-item .history-title-edit {
        font-size: var(--font-size-xs);
      }

      .history-item .actions button {
        min-width: 40px;
        padding: 4px;
      }

      .history-item .actions button i {
        font-size: var(--font-size-sm);
      }

      /* 字幕控制组在平板上 */
      .subtitle-size-color-controls {
        flex-basis: auto; /* 自动调整宽度 */
        flex-grow: 1;
      }
    }

    @media (max-width: 768px) {
      body {
        padding: var(--spacing-sm);
      }

      #app-container {
        width: 100%;
        min-height: auto;
        border-radius: 0; /* 移动端全屏 */
        box-shadow: none;
      }

      .header {
        padding: var(--spacing-xs) var(--spacing-sm);
      }

      .logo h1 {
        display: none; /* 移动端隐藏标题，只显示图标 */
      }

      .header-actions {
        gap: var(--spacing-xs);
      }

      .header-actions #headerHistoryToggleBtn,
      .header-actions #headerSettingsToggleBtn {
        display: flex; /* 确保它们在头部可见 */
      }

      .btn {
        padding: 6px 10px;
        font-size: var(--font-size-xs);
      }

      .btn-icon {
        width: 32px;
        height: 32px;
        font-size: var(--font-size-sm);
      }

      .main-content {
        padding: var(--spacing-sm);
        gap: var(--spacing-sm);
      }

      /* 统一控制行布局 */
      .control-row {
        flex-direction: column; /* 默认堆叠 */
        align-items: flex-start;
        gap: var(--spacing-sm); /* 统一间距 */
      }

      /* 特殊处理播放器顶部控制行，保持一行 */
      #topPlayerControls {
        flex-direction: row;
        justify-content: space-between;
        width: 100%;
        gap: var(--spacing-xs); /* 缩小间距 */
      }
      #topPlayerControls .btn-icon {
        width: 36px; /* 稍微大一点，方便点击 */
        height: 36px;
      }
      #topPlayerControls .time-display {
        min-width: 40px; /* 确保时间显示完整 */
      }
      #topPlayerControls .volume-slider {
        width: 60px;
      }
      #topPlayerControls #volumePercentageDisplay {
        min-width: 30px; /* 适应更小的音量百分比显示 */
      }

      /* 视频内部控制条在移动端始终显示 */
      #inVideoControls {
        background: rgba(0, 0, 0, 0.8); /* 移动端背景更实 */
        padding: var(--spacing-xs); /* 最小化内边距 */
        gap: var(--spacing-xs); /* 最小化元素间距 */
        flex-wrap: nowrap; /* 强制不换行 */
        overflow-inline: hidden; /* 逻辑属性替换 */
        justify-content: space-between; /* 均匀分布 */
      }
      #inVideoControls .btn-icon {
        width: 32px;
        height: 32px;
        font-size: var(--font-size-sm);
        flex-shrink: 0;
      }
      #inVideoControls .time-display {
        font-size: 10px; /* 进一步缩小字体 */
        min-width: 30px; /* 确保有最小宽度 */
        flex-shrink: 0;
      }
      #inVideoControls .seek-slider {
        flex-grow: 1;
        min-width: 40px; /* 确保有最小宽度 */
      }
      #inVideoControls .volume-controls {
        flex-shrink: 0;
        gap: 2px; /* 缩小音量控制内部间距 */
      }
      #inVideoControls .volume-controls i {
          font-size: 14px; /* 缩小音量图标 */
      }
      #inVideoControls .volume-slider {
        width: 30px; /* 进一步缩小 */
      }
      #inVideoControls #inVideoVolumePercentageDisplay {
        font-size: 10px; /* 进一步缩小字体 */
        min-width: 20px;
      }

      /* 输入组和文件上传按钮 */
      .input-group,
      .file-input-wrapper {
        width: 100%; /* 占据整行 */
      }
      .input-group input[type="text"],
      .input-group .btn,
      .file-input-wrapper .btn {
        width: 100%; /* 内部元素也占据整行 */
        min-width: unset;
      }

      /* 按钮组 */
      .btn-group {
        width: 100%;
        justify-content: space-between; /* 按钮之间均匀分布 */
        gap: var(--spacing-xs); /* 缩小按钮组内部间距 */
      }
      .btn-group .btn {
        flex: 1 1 auto; /* 自动分配宽度 */
        min-width: unset;
        padding: 8px 10px; /* 调整按钮内边距 */
        font-size: var(--font-size-xs); /* 调整字体大小 */
      }

      /* 字幕控制组在手机上 */
      .subtitle-controls-group {
        flex-direction: column; /* 堆叠排列 */
        align-items: flex-start;
        width: 100%;
      }
      .subtitle-controls-group .btn {
        width: 100%; /* 按钮占据整行 */
      }
      .subtitle-size-color-controls {
        flex-direction: row; /* 保持在同一行 */
        flex-wrap: wrap;
        width: 100%;
        justify-content: flex-start; /* 左对齐 */
        gap: var(--spacing-sm); /* 保持内部间距 */
      }
      .subtitle-size-color-controls .subtitle-label {
        flex-basis: auto; /* 允许标签自适应 */
        min-width: unset;
      }
      .subtitle-size-color-controls .subtitle-range-slider {
        flex-grow: 1; /* 滑块占据可用空间 */
        min-width: 60px; /* 调整最小宽度 */
      }
      .input-with-unit {
        flex-shrink: 0; /* 防止收缩 */
      }
      .custom-input-number {
        width: 50px; /* 调整宽度 */
        padding: 4px 8px; /* 调整内边距 */
      }
      .custom-input-color {
        width: 36px; /* 调整大小 */
        height: 36px;
        min-width: 36px;
      }

      .history-item .actions {
        width: 100%;
        justify-content: flex-start;
      }

      /* 历史记录循环模式按钮组在移动端 */
      .history-loop-controls {
        justify-content: space-between; /* 均匀分布 */
        gap: var(--spacing-xs); /* 缩小间距 */
      }
      .history-loop-controls .btn {
        flex: 1 1 auto; /* 自动分配宽度 */
        min-width: unset;
        font-size: var(--font-size-xs);
        padding: 6px 8px;
      }
    }
  </style>
</head>
<body>
  <div id="app-container">
    <header class="header">
      <div class="logo">
        <i class="fas fa-play-circle"></i>
        <h1>沉浸式视频播放器</h1>
      </div>
      <div class="header-actions">
        <button class="btn btn-icon btn-secondary" id="themeToggle" aria-label="切换主题">
          <i class="fas fa-moon"></i>
        </button>
        <!-- 新增系统时间显示切换按钮 -->
        <button class="btn btn-icon btn-secondary" id="toggleSystemTimeBtn" aria-label="显示/隐藏系统时间">
          <i class="fas fa-clock"></i>
        <!-- 头部历史记录按钮 (桌面/移动端都可见) -->
        <button class="btn btn-icon btn-secondary" id="headerHistoryToggleBtn" aria-label="打开历史记录">
          <i class="fas fa-history"></i>
        </button>
        <!-- 头部设置按钮 (桌面/移动端都可见) -->
        <button class="btn btn-icon btn-secondary" id="headerSettingsToggleBtn" aria-label="打开设置">
          <i class="fas fa-cog"></i>
        </button>
        </button>
      </div>
    </header>

    <main class="main-content">
      <section class="video-player-section">
        <!-- 上传占位符，默认显示 -->
        <div id="uploadPlaceholder" class="upload-placeholder">
          <i class="fas fa-cloud-upload-alt"></i>
          <h3>拖放视频文件到此处</h3>
          <p>或点击选择本地视频 / 输入在线 URL</p>
          <p class="text-small">支持 MP4, M3U8, FLV, WebM, MKV 等主流格式</p>
        </div>

        <!-- 视频播放器容器，默认隐藏 -->
        <div class="video-container" id="videoContainer">
          <!-- 原生 video 标签，用于 HLS, 原生 MP4 等 -->
          <video id="videoPlayer"></video>
          <!-- xgplayer 容器，默认隐藏，用于 FLV 直播等特殊场景 -->
          <div id="xgplayerContainer" style="display: none;"></div>

          <div id="subtitleDisplay" class="subtitle-display" style="display: none;"></div>
          <!-- 新增系统时间显示元素 -->
          <div id="systemTimeDisplay"></div>

          <!-- 视频内部控制条 -->
          <div id="inVideoControls">
            <button class="btn btn-icon" id="inVideoPlayPauseBtn" aria-label="播放/暂停">
              <i class="fas fa-play"></i>
            </button>
            <div id="inVideoCurrentTimeDisplay" class="time-display">00:00</div>
            <input type="range" min="0" max="0" value="0" step="0.01" class="seek-slider" id="inVideoSeekSlider" aria-label="播放进度">
            <div id="inVideoDurationDisplay" class="time-display">00:00</div>
            <div class="volume-controls">
              <i class="fas fa-volume-up" id="inVideoVolumeIcon" aria-label="音量图标"></i>
              <input type="range" min="0" max="100" value="100" class="volume-slider" id="inVideoVolumeSlider" aria-label="音量调节">
              <span id="inVideoVolumePercentageDisplay">100%</span>
            </div>
            <button class="btn btn-icon" id="inVideoFullscreenBtn" aria-label="全屏">
              <i class="fas fa-expand"></i>
            </button>
          </div>
        </div>
      </section>

      <!-- 主控制条 (在视频下方，包含 URL 输入、上传、速度等) -->
      <section class="main-control-bar">
        <!-- 播放器顶部控制行 (包含播放/暂停、进度条、音量、全屏) -->
        <div class="control-row" id="topPlayerControls">
          <button class="btn btn-icon btn-secondary" id="playPauseBtn" aria-label="播放/暂停">
            <i class="fas fa-play"></i>
          </button>
          <div class="progress-bar-container">
            <div id="currentTimeDisplay" class="time-display">00:00</div>
            <input type="range" min="0" max="0" value="0" step="0.01" class="seek-slider" id="seekSlider" aria-label="播放进度">
            <div id="durationDisplay" class="time-display">00:00</div>
          </div>
          <div class="volume-controls">
            <i class="fas fa-volume-up" id="volumeIcon" aria-label="音量图标"></i>
            <input type="range" min="0" max="100" value="100" class="volume-slider" id="volumeSlider" aria-label="音量调节">
            <span id="volumePercentageDisplay">100%</span> <!-- 音量百分比显示 -->
            <button class="btn btn-icon btn-secondary" id="muteButton" aria-label="静音/取消静音">
              <i class="fas fa-volume-up" id="muteButtonIcon"></i>
            </button>
            <button class="btn btn-icon btn-secondary" onclick="toggleFullscreen()" aria-label="全屏">
              <i class="fas fa-expand"></i>
            </button>
          </div>
        </div>

        <div class="control-row">
          <div class="input-group">
            <input
              type="text"
              id="videoURL"
              placeholder="输入视频URL (支持所有主流视频格式)"
              value="https://sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/hls/xgplayer-demo.m3u8"
              aria-label="视频URL输入框"
            />
            <button class="btn btn-primary" id="loadVideoBtn">
              <i class="fas fa-play"></i> 加载视频
            </button>
            <button class="btn btn-secondary" id="reloadVideoBtn">
              <i class="fas fa-sync-alt"></i> 重新加载
            </button>
            <button class="btn btn-danger" onclick="stopPlayback()">
              <i class="fas fa-stop"></i> 停止播放
            </button>
          </div>
          <div class="file-input-wrapper">
            <button class="btn btn-success" id="uploadLocalBtn">
              <i class="fas fa-upload"></i> 上传本地视频
            </button>
            <!-- 修改：添加 multiple 属性以支持批量上传 -->
            <input
              type="file"
              id="fileInput"
              accept="video/*,.mkv"
              multiple
              aria-label="选择本地视频文件"
            />
          </div>
        </div>

        <div class="control-row">
          <div class="btn-group" id="speedBtnGroup">
            <button class="btn btn-secondary" data-speed="0.5" aria-label="0.5倍速">
              <i class="fas fa-tachometer-alt"></i> 0.5x
            </button>
            <button class="btn btn-secondary" data-speed="1" aria-label="1倍速">
              <i class="fas fa-tachometer-alt"></i> 1x
            </button>
            <button class="btn btn-secondary" data-speed="1.5" aria-label="1.5倍速">
              <i class="fas fa-tachometer-alt"></i> 1.5x
            </button>
            <button class="btn btn-secondary" data-speed="2" aria-label="2倍速">
              <i class="fas fa-tachometer-alt"></i> 2x
            </button>
          </div>
        </div>

        <!-- 新的字幕控制行 -->
        <div class="control-row">
          <div class="subtitle-controls-group">
            <select id="subtitleSelect" class="btn btn-secondary" aria-label="选择字幕">
              <option value="none">无字幕</option>
              <!-- 上传字幕选项将通过JS动态添加 -->
            </select>
            <button class="btn btn-secondary" id="uploadSubtitleBtn" aria-label="上传字幕文件">
              <i class="fas fa-file-upload"></i> 上传字幕
            </button>
            <button class="btn btn-secondary" id="toggleSubtitleBtn" aria-label="显示/隐藏字幕">
              <i class="fas fa-eye-slash"></i> 切换字幕
            </button>
            <button class="btn btn-secondary" onclick="downloadVideo()" aria-label="下载视频">
              <i class="fas fa-download"></i> 下载视频
            </button>
            <!-- 字幕大小和颜色调节 -->
            <div class="subtitle-size-color-controls">
              <label for="subtitleSizeSlider" class="subtitle-label">字幕大小:</label>
              <input type="range" id="subtitleSizeSlider" min="12" max="48" value="20" aria-label="字幕大小" class="subtitle-range-slider" />
              <div class="input-with-unit">
                <input type="number" id="subtitleSizeValue" min="12" max="48" value="20" aria-label="字幕大小数值" class="custom-input-number" />
                <span class="unit-text">px</span>
              </div>
              <label for="subtitleColorPicker" class="subtitle-label">颜色:</label>
              <input type="color" id="subtitleColorPicker" value="#FFFFFF" aria-label="字幕颜色" class="custom-input-color" />
            </div>
          </div>
        </div>

        <div id="statusIndicator" class="status-indicator stopped">
          <i class="fas fa-circle"></i> 播放器已停止
        </div>
      </section>
    </main>
  </div>

  <!-- 设置面板抽屉 -->
  <aside class="drawer-panel settings-panel-drawer" id="settingsPanel">
    <div class="drawer-header">
      <span class="drawer-title-wrapper"><i class="fas fa-cog"></i> 播放器设置</span>
      <button class="close-btn" id="closeSettingsBtn" aria-label="关闭设置面板">
        <i class="fas fa-times"></i>
      </button>
    </div>
    <div class="drawer-content">
      <div class="setting-group">
        <h4><i class="fas fa-image"></i> 背景定制</h4>
        <div class="input-group" style="margin-bottom: var(--spacing-sm);">
          <input type="text" id="backgroundURL" placeholder="背景图片URL" aria-label="背景图片URL" />
          <button class="btn btn-secondary" id="applyBackgroundBtn">应用</button>
        </div>
        <div class="slider-group">
          <label for="backgroundBlurSlider">模糊度:</label>
          <input type="range" id="backgroundBlurSlider" min="0" max="20" step="1" value="5" aria-label="背景模糊度" />
          <span id="backgroundBlurValue">5px</span>
        </div>
        <button class="btn btn-secondary btn-full-width" id="resetBackgroundBtn">
          <i class="fas fa-redo-alt"></i> 重置背景
        </button>
      </div>

      <!-- 字幕样式已移动 -->

      <div class="setting-group">
        <h4><i class="fas fa-film"></i> 画面调节</h4>
        <div class="btn-group" style="margin-bottom: var(--spacing-sm);">
          <button class="btn btn-secondary" id="rotate90Btn"><i class="fas fa-redo-alt"></i> 旋转 90°</button>
          <button class="btn btn-secondary" id="flipXBtn"><i class="fas fa-arrows-alt-h"></i> 水平镜像</button>
          <button class="btn btn-secondary" id="flipYBtn"><i class="fas fa-arrows-alt-v"></i> 垂直镜像</button>
        </div>
        <div class="slider-group">
          <label for="zoomSlider">缩放:</label>
          <input type="range" id="zoomSlider" min="50" max="300" step="1" value="100" aria-label="画面缩放" />
          <span id="zoomValue">100%</span>
        </div>
        <button class="btn btn-secondary btn-full-width" id="resetTransformBtn">
          <i class="fas fa-sync-alt"></i> 重置画面
        </button>
      </div>

      <div class="setting-group">
        <h4><i class="fas fa-palette"></i> 滤镜调节</h4>
        <div class="slider-group">
          <label for="brightnessSlider">亮度:</label>
          <input type="range" id="brightnessSlider" min="0" max="200" step="1" value="100" aria-label="亮度" />
          <span id="brightnessValue">100%</span>
        </div>
        <div class="slider-group">
          <label for="contrastSlider">对比度:</label>
          <input type="range" id="contrastSlider" min="0" max="200" step="1" value="100" aria-label="对比度" />
          <span id="contrastValue">100%</span>
        </div>
        <div class="slider-group">
          <label for="saturationSlider">饱和度:</label>
          <input type="range" id="saturationSlider" min="0" max="200" step="1" value="100" aria-label="饱和度" />
          <span id="saturationValue">100%</span>
        </div>
        <div class="slider-group">
          <label for="sharpenSlider">锐化:</label>
          <input type="range" id="sharpenSlider" min="0" max="10" step="1" value="0" aria-label="锐化" />
          <span id="sharpenValue">0</span>
        </div>

        <div class="btn-group preset-buttons" id="filterPresetsContainer" style="margin-top: var(--spacing-sm);">
          <button class="btn btn-secondary preset-btn" data-preset="vibrant">鲜艳</button>
          <button class="btn btn-secondary preset-btn" data-preset="cinematic">电影</button>
          <button class="btn btn-secondary preset-btn" data-preset="monochrome">黑白</button>
        </div>
        <button class="btn btn-secondary btn-full-width" id="resetFilterBtn">
          <i class="fas fa-sync-alt"></i> 重置滤镜
        </button>
      </div>
    </div>
  </aside>

  <!-- 历史记录面板抽屉 -->
  <aside class="drawer-panel history-panel-drawer" id="historyPanel">
    <div class="drawer-header">
      <span class="drawer-title-wrapper">
        <i class="fas fa-history"></i> <!-- 图标保持在左侧 -->
        <span class="history-title-text">播放历史</span> <!-- 文字左对齐 -->
      </span>
      <button class="close-btn" id="closeHistoryBtn" aria-label="关闭历史记录面板">
        <i class="fas fa-times"></i>
      </button>
    </div>
    <div class="drawer-content">
      <div class="history-loop-controls"> <!-- 新增的循环模式按钮组 -->
        <button class="btn btn-danger btn-sm" onclick="clearHistory()">
          <i class="fas fa-trash"></i> 清空
        </button>
        <button class="btn btn-secondary btn-sm" id="loopSingleBtn" data-loop-mode="single" aria-label="单曲循环">
          <i class="fas fa-redo-alt"></i> 单曲
        </button>
        <button class="btn btn-secondary btn-sm" id="loopListBtn" data-loop-mode="list" aria-label="列表循环">
          <i class="fas fa-list-ul"></i> 列表
        </button>
        <button class="btn btn-secondary btn-sm" id="loopShuffleBtn" data-loop-mode="shuffle" aria-label="随机播放">
          <i class="fas fa-random"></i> 随机
        </button>
      </div>
      <div class="history-list" id="historyList">
        <!-- 历史记录将通过JS动态添加 -->
      </div>
    </div>
  </aside>

  <!-- SVG 滤镜定义，用于锐化效果 -->
  <svg id="sharpen-svg-filters" style="display:none;width:0;height:0;position:absolute;">
    <!-- 滤镜将通过 JavaScript 动态生成 -->
  </svg>

  <script>
    // ====================================================================
    // 全局变量和初始化
    // ====================================================================
    let hlsInstance = null;
    let xgPlayerInstance = null; // xgplayer 实例

    let nativeVideoPlayer = null; // 引用原生的 <video> 元素
    let xgplayerContainerElement = null; // 引用 xgplayer 的 div 容器
    let activePlayer = null; // 当前活跃的播放器 API (可能是 nativeVideoPlayer 或 xgPlayerInstance)
    let currentPlayingMethod = 'none'; // 'none', 'native', 'hls', 'xgplayer'

    let currentVideoUrl = null; // 当前播放视频的URL (可以是网络URL或blob:URL)

    let playbackHistory = JSON.parse(localStorage.getItem('playbackHistory')) || []; // 播放历史记录
    // 修复：确保所有 local 类型且没有 fileObject 的历史记录条目，其 fileObject 属性被显式设置为 null
    playbackHistory = playbackHistory.map(item => {
        if (item.type === 'local' && item.url.startsWith('blob:') && !item.fileObject) {
            item.fileObject = null; // 显式设置为 null 表示 File 对象已丢失
        }
        return item;
    });

    let currentSubtitleTracks = []; // 存储解析后的字幕对象 { start, end, text }
    let subtitleActive = false; // 控制自定义字幕显示是否激活
    let currentSubtitleFileName = null; // 当前加载的字幕文件名
    let isSeeking = false; // 用于标记用户是否正在拖动进度条
    let wasPlayingBeforeSeek = false; // 用于记录拖动进度条前视频是否在播放

    // 新增用于键盘快进/快退的全局变量
    let keyboardSeekTimeout = null;
    let keyboardSeekCurrentTime = 0; // 用于存储键盘快进/快退时的预览时间
    let isKeyboardSeeking = false; // 标记是否正在进行键盘快进/快退操作

    let currentlyEditingIndex = -1; // 用于跟踪当前正在编辑的历史项索引
    let currentLoopMode = localStorage.getItem('loopMode') || 'none'; // 循环模式：'none', 'single', 'list', 'shuffle'
    let currentPlayingHistoryIndex = -1; // 跟踪当前播放的视频在历史记录中的索引

    // 自定义控制条自动隐藏相关
    let controlsHideTimeout = null;
    const controlsVisibleDuration = 3000; // 3秒后自动隐藏

    // 支持的视频格式列表 (用于文件扩展名检查)
    const supportedFormats = [
      'mp4', 'm3u8', 'flv', 'webm', 'mkv', 'mov', 'avi', 'wmv', '3gp', 'ogg', 'mpg', 'mpeg', 'vob', 'ts',
    ];

    // 字幕设置的默认值
    const defaultSubtitleSettings = {
      fontSize: 20,
      // 使用CSS逻辑属性
      color: '#FFFFFF',
    };
    let currentSubtitleSettings = JSON.parse(localStorage.getItem('subtitleSettings')) || defaultSubtitleSettings;

    // 视频画面变换设置
    const defaultTransformSettings = {
      rotate: 0,
      scaleX: 1,
      scaleY: 1,
      zoom: 100,
    };
    let transformSettings = JSON.parse(localStorage.getItem('transformSettings')) || { ...defaultTransformSettings };

    // 视频滤镜设置
    const defaultFilterSettings = {
      brightness: 100,
      contrast: 100,
      saturation: 100,
      sharpen: 0,
    };
    let filterSettings = JSON.parse(localStorage.getItem('filterSettings')) || { ...defaultFilterSettings };

    // 滤镜预设值
    const filterPresets = {
      vibrant: { brightness: 105, contrast: 110, saturation: 150, sharpen: 0 },
      cinematic: { brightness: 95, contrast: 120, saturation: 80, sharpen: 0 },
      monochrome: { brightness: 100, contrast: 100, saturation: 0, sharpen: 0 },
    };

    // 背景设置
    const defaultBackgroundSettings = {
      url: 'https://my.bing.xo.je/302/uhd_302.php', // 初始默认背景图
      blur: 0, // 修改默认模糊度为0
    };
    let backgroundSettings = JSON.parse(localStorage.getItem('backgroundSettings')) || { ...defaultBackgroundSettings };

    // 新增：requestAnimationFrame 相关的全局变量
    let animationFrameId = null; // 用于存储 requestAnimationFrame 的 ID
    let systemTimeIntervalId = null; // 用于存储 setInterval 的 ID
    // 修改：系统时间显示模式，可以是 'background', 'no-background', 'hidden'
    let systemTimeDisplayMode = localStorage.getItem('systemTimeDisplayMode') || 'background';

    // **修复静音 Bug 相关：用于存储静音前的音量，不依赖于 DOM 元素的 dataset**
    let savedVolumeBeforeMute = parseFloat(localStorage.getItem('savedVolumeBeforeMute')) || 1.0; // 初始化为 0.0-1.0 范围的值，默认100%

    // 播放器DOM元素引用 (使用 let 声明，方便在 DOMContentLoaded 中赋值)
    let playPauseBtn,
        uploadPlaceholder, videoContainerElement,
        seekSlider, currentTimeDisplay, durationDisplay,
        volumeSlider, volumeIcon, muteButtonIcon, volumePercentageDisplay,
        subtitleSizeSlider, subtitleSizeValue, subtitleColorPicker, subtitleDisplay,
        settingsPanel, historyPanel,
        rotate90Btn, flipXBtn, flipYBtn, zoomSlider, zoomValueSpan, resetTransformBtn,
        brightnessSlider, brightnessValueSpan, contrastSlider, contrastValueSpan,
        saturationSlider, saturationValueSpan, sharpenSlider, sharpenValueSpan,
        resetFilterBtn, filterPresetsContainer, speedBtnGroup,
        backgroundURLInput, backgroundBlurSlider, backgroundBlurValueSpan, applyBackgroundBtn, resetBackgroundBtn,
        headerSettingsToggleBtn, headerHistoryToggleBtn,
        // 视频内部控制条元素
        inVideoControls, inVideoPlayPauseBtn, inVideoPlayPauseIcon,
        inVideoSeekSlider, inVideoCurrentTimeDisplay, inVideoDurationDisplay,
        inVideoVolumeSlider, inVideoVolumeIcon, inVideoVolumePercentageDisplay, inVideoFullscreenBtn,
        loopSingleBtn, loopListBtn, loopShuffleBtn,
        systemTimeDisplayElement, toggleSystemTimeBtn; // 新增系统时间相关元素

    // ====================================================================
    // DOMContentLoaded 事件监听器
    // ====================================================================
    document.addEventListener('DOMContentLoaded', function () {
      // 获取DOM元素引用
      nativeVideoPlayer = document.getElementById('videoPlayer'); // 原生 video 元素
      xgplayerContainerElement = document.getElementById('xgplayerContainer'); // xgplayer 容器
      activePlayer = nativeVideoPlayer; // 初始活跃播放器为原生 video

      playPauseBtn = document.getElementById('playPauseBtn');
      playPauseIcon = playPauseBtn.querySelector('i');
      uploadPlaceholder = document.getElementById('uploadPlaceholder');
      videoContainerElement = document.getElementById('videoContainer');
      seekSlider = document.getElementById('seekSlider');
      currentTimeDisplay = document.getElementById('currentTimeDisplay');
      durationDisplay = document.getElementById('durationDisplay');
      volumeSlider = document.getElementById('volumeSlider');
      volumeIcon = document.getElementById('volumeIcon');
      muteButtonIcon = document.getElementById('muteButtonIcon');
      volumePercentageDisplay = document.getElementById('volumePercentageDisplay');
      subtitleSizeSlider = document.getElementById('subtitleSizeSlider');
      subtitleSizeValue = document.getElementById('subtitleSizeValue');
      subtitleColorPicker = document.getElementById('subtitleColorPicker');
      subtitleDisplay = document.getElementById('subtitleDisplay');
      systemTimeDisplayElement = document.getElementById('systemTimeDisplay'); // 获取系统时间显示元素
      toggleSystemTimeBtn = document.getElementById('toggleSystemTimeBtn'); // 获取系统时间切换按钮

      settingsPanel = document.getElementById('settingsPanel');
      historyPanel = document.getElementById('historyPanel');

      // 画面调节
      rotate90Btn = document.getElementById('rotate90Btn');
      flipXBtn = document.getElementById('flipXBtn');
      flipYBtn = document.getElementById('flipYBtn');
      zoomSlider = document.getElementById('zoomSlider');
      zoomValueSpan = document.getElementById('zoomValue');
      resetTransformBtn = document.getElementById('resetTransformBtn');

      // 滤镜调节
      brightnessSlider = document.getElementById('brightnessSlider');
      brightnessValueSpan = document.getElementById('brightnessValue');
      contrastSlider = document.getElementById('contrastSlider');
      contrastValueSpan = document.getElementById('contrastValue');
      saturationSlider = document.getElementById('saturationSlider');
      saturationValueSpan = document.getElementById('saturationValue');
      sharpenSlider = document.getElementById('sharpenSlider');
      sharpenValueSpan = document.getElementById('sharpenValue');
      resetFilterBtn = document.getElementById('resetFilterBtn');
      filterPresetsContainer = document.getElementById('filterPresetsContainer');

      // 速度控制组
      speedBtnGroup = document.getElementById('speedBtnGroup');

      // 背景定制
      backgroundURLInput = document.getElementById('backgroundURL');
      backgroundBlurSlider = document.getElementById('backgroundBlurSlider');
      backgroundBlurValueSpan = document.getElementById('backgroundBlurValue');
      applyBackgroundBtn = document.getElementById('applyBackgroundBtn');
      resetBackgroundBtn = document.getElementById('resetBackgroundBtn');

      // 头部切换按钮
      headerSettingsToggleBtn = document.getElementById('headerSettingsToggleBtn');
      headerHistoryToggleBtn = document.getElementById('headerHistoryToggleBtn');

      // 视频内部控制条元素
      inVideoControls = document.getElementById('inVideoControls');
      inVideoPlayPauseBtn = document.getElementById('inVideoPlayPauseBtn');
      inVideoPlayPauseIcon = inVideoPlayPauseBtn.querySelector('i');
      inVideoSeekSlider = document.getElementById('inVideoSeekSlider');
      inVideoCurrentTimeDisplay = document.getElementById('inVideoCurrentTimeDisplay');
      inVideoDurationDisplay = document.getElementById('inVideoDurationDisplay');
      inVideoVolumeSlider = document.getElementById('inVideoVolumeSlider');
      inVideoVolumeIcon = document.getElementById('inVideoVolumeIcon');
      inVideoVolumePercentageDisplay = document.getElementById('inVideoVolumePercentageDisplay');
      inVideoFullscreenBtn = document.getElementById('inVideoFullscreenBtn');

      // 循环模式按钮
      loopSingleBtn = document.getElementById('loopSingleBtn');
      loopListBtn = document.getElementById('loopListBtn');
      loopShuffleBtn = document.getElementById('loopShuffleBtn');

      // 加载主题设置
      loadTheme();

      // 渲染历史记录
      renderHistory();

      // 设置拖放区域功能
      setupDragAndDrop();

      // 点击上传占位符区域触发文件选择
      uploadPlaceholder.addEventListener('click', () => {
          if (!videoContainerElement.classList.contains('visible')) {
              document.getElementById('fileInput').click();
          }
      });

      // 设置播放器事件监听 (包含进度条)
      setupPlayerEvents();

      // 设置音量控制
      setupVolumeControl();
      setupInVideoVolumeControl(); // 新增：设置视频内部音量控制

      // 设置字幕样式控制
      setupSubtitleSettings();

      // 设置侧边抽屉面板的开关逻辑
      setupPanelToggles();

      // 设置画面调节和滤镜控制
      setupVideoSettingsControls();

      // 设置背景定制功能
      setupBackgroundCustomization();

      // 创建锐化滤镜的 SVG 元素
      createSharpenSVGElements();

      // 加载所有保存的设置 (字幕、画面、滤镜、播放速度、背景)
      loadAllSettings();

      // 初始加载系统时间显示状态并启动更新
      loadSystemTimeVisibility();
      startSystemTimeUpdate();
      toggleSystemTimeBtn.addEventListener('click', toggleSystemTimeVisibility); // 绑定按钮事件

      // 绑定上传本地视频按钮
      document.getElementById('uploadLocalBtn').addEventListener('click', () => {
        document.getElementById('fileInput').click();
      });

      // 绑定上传字幕按钮
      document.getElementById('uploadSubtitleBtn').addEventListener('click', () => {
        uploadSubtitleFile();
      });

      // 监听本地视频文件选择
      // 修改：接受 FileList 以支持批量上传
      document.getElementById('fileInput').addEventListener('change', function () {
        if (this.files && this.files.length > 0) {
          playLocalVideo(this.files); // 传递 FileList
          this.value = ''; // 清空，允许重复上传同一个文件也触发
        }
      });

      // 绑定加载视频按钮的点击事件 (取代了原来的 playPauseBtn 的加载功能)
      document.getElementById('loadVideoBtn').addEventListener('click', () => {
        const inputUrl = document.getElementById('videoURL').value.trim();
        if (inputUrl) {
          play(inputUrl);
        } else {
          alert('请输入视频URL！');
        }
      });

      // 绑定重新加载按钮的点击事件
      document.getElementById('reloadVideoBtn').addEventListener('click', reloadVideo);

      // 绑定URL输入框的回车事件
      document.getElementById('videoURL').addEventListener('keydown', (e) => {
        if (e.key === 'Enter') {
          e.preventDefault();
          document.getElementById('loadVideoBtn').click();
        }
      });

      // 绑定播放/暂停按钮的点击事件 (仅切换播放状态，不加载新视频)
      playPauseBtn.addEventListener('click', togglePlayPause);
      inVideoPlayPauseBtn.addEventListener('click', togglePlayPause); // 视频内部控制条的播放/暂停按钮

      // 绑定视频内部控制条的全屏按钮
      inVideoFullscreenBtn.addEventListener('click', toggleFullscreen);

      // 为历史记录列表添加事件委托，处理编辑/保存按钮点击
      document.getElementById('historyList').addEventListener('click', function(e) {
        const targetBtn = e.target.closest('.edit-save-btn');
        if (targetBtn) {
          const index = parseInt(targetBtn.dataset.index);
          const action = targetBtn.dataset.action;

          if (action === 'edit') {
            startEditMode(index);
          } else if (action === 'save' && currentlyEditingIndex === index) {
            saveEditMode(index);
          }
        }
      });

      // 监听全屏状态变化，以便调整视频样式
      document.addEventListener('fullscreenchange', handleFullscreenChange);

      // 绑定播放速度按钮
      speedBtnGroup.addEventListener('click', (e) => {
        const targetBtn = e.target.closest('.btn');
        if (targetBtn && targetBtn.dataset.speed) {
          changeSpeed(parseFloat(targetBtn.dataset.speed), targetBtn);
        }
      });

      // 绑定字幕显示/隐藏按钮
      document.getElementById('toggleSubtitleBtn').addEventListener('click', toggleSubtitle);

      // 绑定静音按钮的点击事件
      document.getElementById('muteButton').addEventListener('click', toggleMute);

      // 添加全局点击事件监听器，用于关闭面板
      document.addEventListener('click', handleOutsideClick);

      // 绑定键盘事件
      document.addEventListener('keydown', handleKeyDown);

      // 绑定视频双击事件
      nativeVideoPlayer.addEventListener('dblclick', toggleFullscreen); // 双击原生视频全屏
      // 修复双击全屏问题：为 xgplayer 容器也添加双击事件监听器
      xgplayerContainerElement.addEventListener('dblclick', toggleFullscreen);

      // 绑定循环模式按钮事件
      document.querySelector('.history-loop-controls').addEventListener('click', (e) => {
          const targetBtn = e.target.closest('.btn');
          if (targetBtn && targetBtn.dataset.loopMode) {
              setLoopMode(targetBtn.dataset.loopMode);
          }
      });
      updateLoopModeButtons(); // 初始化循环模式按钮状态

      // --- 自定义控制条自动隐藏/显示逻辑 ---
      // 初始状态：如果不是桌面端，则显示控制条并启动隐藏计时器
      if (window.innerWidth <= 768) { // Mobile
        inVideoControls.classList.add('controls-visible');
        resetHideTimer(); // Start hide timer for mobile
      } else { // Desktop
        // Controls start hidden, will show on mousemove
        inVideoControls.classList.remove('controls-visible');
      }

      // 桌面端鼠标事件
      if (window.innerWidth > 768) {
        videoContainerElement.addEventListener('mousemove', showControls);
        videoContainerElement.addEventListener('mouseleave', resetHideTimer);
        // PC端点击视频区域播放/暂停 - 移除，由全局 videoContainerElement.addEventListener('click') 处理
        // nativeVideoPlayer.addEventListener('click', togglePlayPause);
        // xgplayerContainerElement.addEventListener('click', togglePlayPause);

        // 确保在控制条元素上移动鼠标也能保持显示
        inVideoControls.addEventListener('mousemove', showControls);
        inVideoControls.addEventListener('mousedown', showControls);
        inVideoControls.addEventListener('mouseup', showControls);
        inVideoControls.addEventListener('mouseleave', resetHideTimer);

        // 任何对控制条内部交互元素的鼠标事件都应重置计时器
        const interactiveElements = inVideoControls.querySelectorAll('button, input[type="range"]');
        interactiveElements.forEach(el => {
          el.addEventListener('mousemove', showControls);
          el.addEventListener('mousedown', showControls);
          el.addEventListener('mouseup', showControls);
        });
      } else { // 移动端点击事件 - 移除，由全局 videoContainerElement.addEventListener('click') 处理
        // videoContainerElement.addEventListener('click', function() { /* ... removed ... */ });
      }

      // 视频播放时显示控制条并启动计时器
      nativeVideoPlayer.addEventListener('play', function() {
        startProgressBarUpdate(); // 启动 requestAnimationFrame 循环
        showControls();
      });

      // 视频暂停时保持控制条显示，停止计时器
      nativeVideoPlayer.addEventListener('pause', function () {
            stopProgressBarUpdate(); // 停止 requestAnimationFrame 循环
            // 仅当不是拖动或键盘快进/快退导致的暂停时，才显示“播放已暂停”
            if (!isSeeking && !isKeyboardSeeking) {
                updateStatus('stopped', '播放已暂停');
            }
            playPauseIcon.className = 'fas fa-play';
            inVideoPlayPauseIcon.className = 'fas fa-play';
            
            // --- MODIFICATION START ---
            // 根据桌面/移动端区分暂停时的控制条显示逻辑
            if (activePlayer && window.innerWidth > 768) { // PC端
              // 在PC端暂停时，显示控制条，并启动自动隐藏计时器
              showControls(); // showControls 会添加 'controls-visible' 并调用 resetHideTimer
            } else { // 移动端 或 activePlayer 不存在时 (保持原有行为，即控制条长期可见)
              clearTimeout(controlsHideTimeout); // 清除任何现有隐藏计时器
              inVideoControls.classList.add('controls-visible'); // 强制控制条可见
            }
            // --- MODIFICATION END ---
        });

      nativeVideoPlayer.addEventListener('waiting', function () {
          if (currentPlayingMethod !== 'xgplayer') {
              updateStatus('loading', '正在缓冲...');
          }
      });

      nativeVideoPlayer.addEventListener('ended', handleVideoEnded);

      nativeVideoPlayer.addEventListener('error', handleVideoError);

      // 绑定全局 seeked 事件处理器
      nativeVideoPlayer.addEventListener('seeked', globalSeekedHandler);

      // 进度条拖动事件 (PC端)
      seekSlider.addEventListener('mousedown', handleSeekStart);
      seekSlider.addEventListener('mouseup', handleSeekEnd);
      inVideoSeekSlider.addEventListener('mousedown', handleSeekStart);
      inVideoSeekSlider.addEventListener('mouseup', handleSeekEnd);

      // 进度条拖动事件 (移动端)
      seekSlider.addEventListener('touchstart', handleSeekStart);
      seekSlider.addEventListener('touchend', handleSeekEnd);
      inVideoSeekSlider.addEventListener('touchstart', handleSeekStart);
      inVideoSeekSlider.addEventListener('touchend', handleSeekEnd);

      seekSlider.addEventListener('input', function() {
          currentTimeDisplay.textContent = formatTime(this.value);
          inVideoSeekSlider.value = this.value; // 同步视频内部进度条
          inVideoCurrentTimeDisplay.textContent = formatTime(this.value); // 同步视频内部时间
      });
      inVideoSeekSlider.addEventListener('input', function() {
          inVideoCurrentTimeDisplay.textContent = formatTime(this.value);
          seekSlider.value = this.value; // 同步外部进度条
          currentTimeDisplay.textContent = formatTime(this.value); // 同步外部时间
      });

      // ====================================================================
      // URL 参数支持功能 - 自动播放通过 src 参数传递的视频链接
      // ====================================================================

      // 解析 URL 参数
      const urlParams = new URLSearchParams(window.location.search);
      const srcParam = urlParams.get('src');

      if (srcParam) {
        try {
          // 解码 URL 参数值，支持编码的 URL
          const decodedSrc = decodeURIComponent(srcParam);

          // 验证是否为有效的 URL
          if (decodedSrc && (decodedSrc.startsWith('http://') || decodedSrc.startsWith('https://'))) {
            // 延迟一小段时间确保所有初始化完成
            setTimeout(() => {
              console.log('检测到 URL 参数 src，自动加载视频:', decodedSrc);
              play(decodedSrc);
            }, 100);
          } else {
            console.warn('URL 参数 src 不是有效的 HTTP/HTTPS 链接:', decodedSrc);
          }
        } catch (error) {
          console.error('解析 URL 参数 src 时出错:', error);
        }
      }

      // --- 新增：统一处理 videoContainerElement 的点击事件 (桌面和移动端) ---
      videoContainerElement.addEventListener('click', function(e) {
        // 检查点击目标是否是视频内部控制条的任何交互元素
        const isInteractiveControl = e.target.closest('#inVideoControls button, #inVideoControls input');

        if (isInteractiveControl) {
            // 如果点击的是内部控制，则让其默认行为发生，不触发视频区域的播放/暂停
            return;
        }

        if (window.innerWidth <= 768) { // 移动端逻辑
            // 移动端：第一次点击通常显示/隐藏控制条，并可能伴随播放/暂停
            if (activePlayer && activePlayer.paused) {
                // 如果是暂停状态，点击视频区域尝试播放并确保显示控制条
                activePlayer.play().catch(err => console.error("Mobile play failed:", err));
                showControls(); // 播放时也确保控制条可见 (并启动隐藏计时器)
            } else if (activePlayer && !activePlayer.paused) {
                // 如果是播放状态，点击则暂停并显示控制条
                activePlayer.pause();
                showControls(); // 暂停时也确保控制条可见 (并清除隐藏计时器)
            } else {
                // 如果没有activePlayer，或者点击仅为了切换controls
                if (inVideoControls.classList.contains('controls-visible')) {
                    hideControls();
                    clearTimeout(controlsHideTimeout);
                } else {
                    showControls();
                }
            }
        } else { // 桌面端逻辑
            // 桌面端：点击视频区域通常只用于切换播放/暂停
            if (activePlayer) {
                togglePlayPause();
            }
        }
      });
      // --- 结束统一点击事件添加 ---

    });

    // ====================================================================
    // 新增：requestAnimationFrame 进度条更新逻辑
    // ====================================================================

    /**
     * 启动 requestAnimationFrame 循环来平滑更新进度条和时间显示。
     */
    function startProgressBarUpdate() {
        if (animationFrameId) {
            cancelAnimationFrame(animationFrameId); // 取消之前的循环
        }
        animationFrameId = requestAnimationFrame(updateProgressBarFrame);
    }

    /**
     * 停止 requestAnimationFrame 循环。
     */
    function stopProgressBarUpdate() {
        if (animationFrameId) {
            cancelAnimationFrame(animationFrameId);
            animationFrameId = null;
        }
    }

    /**
     * requestAnimationFrame 回调函数，用于更新进度条和时间显示。
     */
    function updateProgressBarFrame() {
        if (!activePlayer || activePlayer.paused || isSeeking || isKeyboardSeeking) {
            // 如果播放器不存在、暂停、正在手动拖动或正在键盘快进/快退，则不更新，并停止循环
            stopProgressBarUpdate();
            return;
        }

        // 确保 duration 是有效数字，避免 NaN
        const duration = isNaN(activePlayer.duration) || activePlayer.duration === Infinity ? 0 : activePlayer.duration;
        const currentTime = Math.max(0, Math.min(activePlayer.currentTime, duration)); // 确保当前时间在有效范围内

        // 更新进度条的最大值（如果视频时长变化）
        if (seekSlider.max !== duration.toString()) {
            seekSlider.max = duration;
            inVideoSeekSlider.max = duration;
            durationDisplay.textContent = formatTime(duration);
            inVideoDurationDisplay.textContent = formatTime(duration);
        }

        // 更新当前时间显示和进度条位置
        seekSlider.value = currentTime;
        inVideoSeekSlider.value = currentTime;
        currentTimeDisplay.textContent = formatTime(currentTime);
        inVideoCurrentTimeDisplay.textContent = formatTime(currentTime);

        if (subtitleActive && currentSubtitleTracks.length > 0) {
            updateSubtitleDisplay(currentTime);
        } else {
            subtitleDisplay.textContent = '';
            subtitleDisplay.style.display = 'none';
        }

        // 请求下一帧
        animationFrameId = requestAnimationFrame(updateProgressBarFrame);
    }

    // ====================================================================
    // 新增：系统时间显示逻辑
    // ====================================================================

    /**
     * 更新系统时间显示。
     */
    function updateSystemTime() {
        const now = new Date();
        const hours = now.getHours().toString().padStart(2, '0');
        const minutes = now.getMinutes().toString().padStart(2, '0');
        const seconds = now.getSeconds().toString().padStart(2, '0');
        systemTimeDisplayElement.textContent = `${hours}:${minutes}:${seconds}`;
    }

    /**
     * 启动系统时间更新计时器。
     */
    function startSystemTimeUpdate() {
        if (systemTimeIntervalId) {
            clearInterval(systemTimeIntervalId);
        }
        updateSystemTime(); // 立即更新一次
        systemTimeIntervalId = setInterval(updateSystemTime, 1000); // 每秒更新
    }

    /**
     * 停止系统时间更新计时器。
     */
    function stopSystemTimeUpdate() {
        if (systemTimeIntervalId) {
            clearInterval(systemTimeIntervalId);
            systemTimeIntervalId = null;
        }
    }

    /**
     * 切换系统时间显示可见性。
     */
    function toggleSystemTimeVisibility() {
        if (systemTimeDisplayMode === 'background') {
            systemTimeDisplayMode = 'no-background';
            systemTimeDisplayElement.classList.remove('hidden');
            systemTimeDisplayElement.classList.add('no-background-time');
            toggleSystemTimeBtn.querySelector('i').className = 'far fa-clock'; // 空心时钟
        } else if (systemTimeDisplayMode === 'no-background') {
            systemTimeDisplayMode = 'hidden';
            systemTimeDisplayElement.classList.add('hidden');
            systemTimeDisplayElement.classList.remove('no-background-time'); // 确保移除无背景类
            toggleSystemTimeBtn.querySelector('i').className = 'fas fa-eye-slash'; // 斜杠眼睛
        } else { // 'hidden'
            systemTimeDisplayMode = 'background';
            systemTimeDisplayElement.classList.remove('hidden');
            systemTimeDisplayElement.classList.remove('no-background-time'); // 确保移除无背景类
            toggleSystemTimeBtn.querySelector('i').className = 'fas fa-clock'; // 实心时钟
        }
        localStorage.setItem('systemTimeDisplayMode', systemTimeDisplayMode);
    }

    /**
     * 从 localStorage 加载系统时间可见性状态。
     */
    function loadSystemTimeVisibility() {
        systemTimeDisplayMode = localStorage.getItem('systemTimeDisplayMode') || 'background'; // 默认显示背景模式

        // 应用初始状态
        if (systemTimeDisplayMode === 'hidden') {
            systemTimeDisplayElement.classList.add('hidden');
            systemTimeDisplayElement.classList.remove('no-background-time');
            toggleSystemTimeBtn.querySelector('i').className = 'fas fa-eye-slash';
        } else if (systemTimeDisplayMode === 'no-background') {
            systemTimeDisplayElement.classList.remove('hidden');
            systemTimeDisplayElement.classList.add('no-background-time');
            toggleSystemTimeBtn.querySelector('i').className = 'far fa-clock';
        } else { // 'background'
            systemTimeDisplayElement.classList.remove('hidden');
            systemTimeDisplayElement.classList.remove('no-background-time');
            toggleSystemTimeBtn.querySelector('i').className = 'fas fa-clock';
        }
    }

    // ====================================================================
    // UI/UX 交互功能
    // ====================================================================

    /**
     * 显示视频内部控制条并重置自动隐藏计时器。
     */
    function showControls() {
      inVideoControls.classList.add('controls-visible');
      resetHideTimer();
    }

    /**
     * 隐藏视频内部控制条。
     */
    function hideControls() {
      inVideoControls.classList.remove('controls-visible');
    }

    /**
     * 重置自动隐藏计时器。
     * - 在桌面端 (PC)，无论视频是播放还是暂停，只要有用户交互（如鼠标移动、点击），都会启动计时器，在指定时间后自动隐藏控制条。
     * - 在移动端，只有当视频处于播放状态时，用户交互才会启动计时器自动隐藏。如果视频暂停，控制条将保持可见（与原行为一致）。
     */
    function resetHideTimer() {
        clearTimeout(controlsHideTimeout);

        if (!activePlayer) return; // 如果没有活跃的播放器，则不启动任何隐藏计时器。

        const isDesktop = window.innerWidth > 768; // 判断是否为桌面端

        if (isDesktop) {
            // 在桌面端，无论播放还是暂停，只要有交互，就启动计时器自动隐藏
            controlsHideTimeout = setTimeout(hideControls, controlsVisibleDuration);
        } else { // 移动端
            // 移动端保持原有逻辑：只有在播放时才启动自动隐藏计时器。
            // 如果移动端是暂停状态，则不启动自动隐藏计时器，让控制条保持可见。
            if (!activePlayer.paused) {
                controlsHideTimeout = setTimeout(hideControls, controlsVisibleDuration);
            }
        }
    }

    /**
     * 处理点击事件，用于关闭侧边抽屉面板。
     * 如果点击发生在面板外部或触发按钮外部，则关闭面板。
     */
    function handleOutsideClick(event) {
        // 头部按钮
        const headerSettingsToggleBtn = document.getElementById('headerSettingsToggleBtn');
        const headerHistoryToggleBtn = document.getElementById('headerHistoryToggleBtn');
        const toggleSystemTimeBtn = document.getElementById('toggleSystemTimeBtn'); // 新增

        // 检查点击是否在设置面板或其触发按钮之外
        const isClickInsideSettingsPanel = settingsPanel.contains(event.target) ||
                                           (headerSettingsToggleBtn && headerSettingsToggleBtn.contains(event.target));
        if (settingsPanel.classList.contains('open') && !isClickInsideSettingsPanel) {
            settingsPanel.classList.remove('open');
        }

        // 检查点击是否在历史面板或其触发按钮之外
        const isClickInsideHistoryPanel = historyPanel.contains(event.target) ||
                                          (headerHistoryToggleBtn && headerHistoryToggleBtn.contains(event.target));
        if (historyPanel.classList.contains('open') && !isClickInsideHistoryPanel) {
            historyPanel.classList.remove('open');
        }
    }

    /**
     * 处理全屏状态变化，调整视频容器样式。
     */
    function handleFullscreenChange() {
        if (document.fullscreenElement) {
            videoContainerElement.classList.add('fullscreen-active');
            showControls(); // 进入全屏时显示控制条并启动计时器
        } else {
            videoContainerElement.classList.remove('fullscreen-active');
            // 退出全屏时，根据当前设备类型恢复控制条的显示逻辑
            if (window.innerWidth > 768) { // 桌面端
                resetHideTimer(); // 启动自动隐藏计时器
            } else { // 移动端
                // 如果控制条当前可见，也启动隐藏计时器
                if (inVideoControls.classList.contains('controls-visible')) {
                    resetHideTimer();
                }
            }
        }
        applyVideoTransformations(); // 全屏/退出全屏后重新应用变换
        applyVideoFilters(); // 全屏/退出全屏后重新应用滤镜
    }

    /**
     * 设置侧边抽屉面板的开关逻辑。
     */
    function setupPanelToggles() {
      // 头部按钮监听 (桌面/移动端通用)
      if (headerSettingsToggleBtn) {
        headerSettingsToggleBtn.addEventListener('click', (e) => {
          e.stopPropagation();
          settingsPanel.classList.toggle('open');
          historyPanel.classList.remove('open'); // 关闭另一个面板
          adjustPanelTopPosition(settingsPanel); // 调整面板位置
        });
      }
      if (headerHistoryToggleBtn) {
        headerHistoryToggleBtn.addEventListener('click', (e) => {
          e.stopPropagation();
          historyPanel.classList.toggle('open');
          settingsPanel.classList.remove('open'); // 关闭另一个面板
          adjustPanelTopPosition(historyPanel); // 调整面板位置
        });
      }

      // 关闭按钮
      document.getElementById('closeSettingsBtn').addEventListener('click', () => {
        settingsPanel.classList.remove('open');
      });
      document.getElementById('closeHistoryBtn').addEventListener('click', () => {
        historyPanel.classList.remove('open');
      });
    }

    /**
     * 根据头部高度调整面板的 top 位置，确保不被遮挡。
     */
    function adjustPanelTopPosition(panel) {
      const header = document.querySelector('.header');
      if (header && panel) {
        const headerHeight = header.offsetHeight;
        // 考虑到 body 的 padding-top (var(--spacing-md))
        const bodyPaddingTop = parseFloat(getComputedStyle(document.body).paddingTop);
        panel.style.top = `${headerHeight + bodyPaddingTop + 10}px`; // 头部高度 + body顶部内边距 + 额外间距
        panel.style.maxHeight = `calc(100vh - ${headerHeight + bodyPaddingTop + 20}px)`; // 调整最大高度
      }
    }

    /**
     * 设置视频画面调节和滤镜控制。
     */
    function setupVideoSettingsControls() {
      // 画面变换控制
      rotate90Btn.addEventListener('click', () => {
        transformSettings.rotate = (transformSettings.rotate + 90) % 360;
        applyVideoTransformations();
        saveAllSettings();
      });

      flipXBtn.addEventListener('click', () => {
        transformSettings.scaleX *= -1;
        applyVideoTransformations();
        saveAllSettings();
      });

      flipYBtn.addEventListener('click', () => {
        transformSettings.scaleY *= -1;
        applyVideoTransformations();
        saveAllSettings();
      });

      zoomSlider.addEventListener('input', () => {
        transformSettings.zoom = parseInt(zoomSlider.value);
        zoomValueSpan.textContent = `${transformSettings.zoom}%`;
        applyVideoTransformations();
        saveAllSettings();
      });

      resetTransformBtn.addEventListener('click', () => {
        Object.assign(transformSettings, defaultTransformSettings);
        zoomSlider.value = transformSettings.zoom;
        zoomValueSpan.textContent = `${transformSettings.zoom}%`;
        applyVideoTransformations();
        saveAllSettings();
      });

      // 视频滤镜控制
      brightnessSlider.addEventListener('input', () => {
        filterSettings.brightness = parseInt(brightnessSlider.value);
        brightnessValueSpan.textContent = `${filterSettings.brightness}%`;
        clearActiveFilterPreset();
        applyVideoFilters();
        saveAllSettings();
      });

      contrastSlider.addEventListener('input', () => {
        filterSettings.contrast = parseInt(contrastSlider.value);
        contrastValueSpan.textContent = `${filterSettings.contrast}%`;
        clearActiveFilterPreset();
        applyVideoFilters();
        saveAllSettings();
      });

      saturationSlider.addEventListener('input', () => {
        filterSettings.saturation = parseInt(saturationSlider.value);
        saturationValueSpan.textContent = `${filterSettings.saturation}%`;
        clearActiveFilterPreset();
        applyVideoFilters();
        saveAllSettings();
      });

      sharpenSlider.addEventListener('input', () => {
        filterSettings.sharpen = parseInt(sharpenSlider.value);
        sharpenValueSpan.textContent = `${filterSettings.sharpen}`;
        clearActiveFilterPreset();
        applyVideoFilters();
        saveAllSettings();
      });

      resetFilterBtn.addEventListener('click', () => {
        Object.assign(filterSettings, defaultFilterSettings);
        updateFilterSlidersUI();
        clearActiveFilterPreset();
        applyVideoFilters();
        saveAllSettings();
      });

      filterPresetsContainer.addEventListener('click', (e) => {
        const targetBtn = e.target.closest('.preset-btn');
        if (targetBtn && targetBtn.dataset.preset) {
          const preset = filterPresets[targetBtn.dataset.preset];
          if (preset) {
            Object.assign(filterSettings, preset);
            updateFilterSlidersUI();
            clearActiveFilterPreset();
            targetBtn.classList.add('active-preset');
            applyVideoFilters();
            saveAllSettings();
          }
        }
      });
    }

    /**
     * 设置背景定制功能。
     */
    function setupBackgroundCustomization() {
      backgroundURLInput.value = backgroundSettings.url;
      backgroundBlurSlider.value = backgroundSettings.blur;
      backgroundBlurValueSpan.textContent = `${backgroundSettings.blur}px`;
      applyBackground(); // 初始应用

      applyBackgroundBtn.addEventListener('click', () => {
        backgroundSettings.url = backgroundURLInput.value.trim();
        applyBackground();
        saveAllSettings();
      });

      backgroundBlurSlider.addEventListener('input', () => {
        backgroundSettings.blur = parseInt(backgroundBlurSlider.value);
        backgroundBlurValueSpan.textContent = `${backgroundSettings.blur}px`;
        applyBackground();
        saveAllSettings();
      });

      resetBackgroundBtn.addEventListener('click', () => {
        Object.assign(backgroundSettings, defaultBackgroundSettings);
        backgroundURLInput.value = backgroundSettings.url;
        backgroundBlurSlider.value = backgroundSettings.blur;
        backgroundBlurValueSpan.textContent = `${backgroundSettings.blur}px`;
        applyBackground();
        saveAllSettings();
      });
    }

    /**
     * 应用背景图片和模糊度。
     */
    function applyBackground() {
      // 如果 backgroundSettings.url 为空字符串，则不设置背景图片
      const imageUrl = backgroundSettings.url ? `url('${backgroundSettings.url}')` : 'none';
      document.body.style.setProperty('--player-bg-image', imageUrl);
      document.body.style.setProperty('--player-bg-blur', `${backgroundSettings.blur}px`);
    }

    /**
     * 应用视频画面变换。
     */
    function applyVideoTransformations() {
      // 应用到原生 video 元素
      if (nativeVideoPlayer && currentPlayingMethod !== 'xgplayer') {
          nativeVideoPlayer.style.transform = `rotate(${transformSettings.rotate}deg) scaleX(${transformSettings.scaleX}) scaleY(${transformSettings.scaleY}) scale(${transformSettings.zoom / 100})`;
      }
      // 应用到 xgplayer 内部的 video 元素
      if (xgPlayerInstance && xgPlayerInstance.video && currentPlayingMethod === 'xgplayer') {
          xgPlayerInstance.video.style.transform = `rotate(${transformSettings.rotate}deg) scaleX(${transformSettings.scaleX}) scaleY(${transformSettings.scaleY}) scale(${transformSettings.zoom / 100})`;
      }
    }

    /**
     * 应用视频滤镜。
     */
    function applyVideoFilters() {
      let filterStyle = `brightness(${filterSettings.brightness}%) contrast(${filterSettings.contrast}%) saturate(${filterSettings.saturation}%)`;
      if (filterSettings.sharpen > 0 && filterSettings.sharpen <= 10) {
        // 使用 SVG 滤镜进行锐化
        filterStyle += ` url(#sharpen-filter-${filterSettings.sharpen})`;
      }
      // 应用到原生 video 元素
      if (nativeVideoPlayer && currentPlayingMethod !== 'xgplayer') {
          nativeVideoPlayer.style.filter = filterStyle;
      }
      // 应用到 xgplayer 内部的 video 元素
      if (xgPlayerInstance && xgPlayerInstance.video && currentPlayingMethod === 'xgplayer') {
          xgPlayerInstance.video.style.filter = filterStyle;
      }
    }

    /**
     * 更新滤镜滑块 UI。
     */
    function updateFilterSlidersUI() {
      brightnessSlider.value = filterSettings.brightness;
      brightnessValueSpan.textContent = `${filterSettings.brightness}%`;
      contrastSlider.value = filterSettings.contrast;
      contrastValueSpan.textContent = `${filterSettings.contrast}%`;
      saturationSlider.value = filterSettings.saturation;
      saturationValueSpan.textContent = `${filterSettings.saturation}%`;
      sharpenSlider.value = filterSettings.sharpen;
      sharpenValueSpan.textContent = `${filterSettings.sharpen}`;
    }

    /**
     * 清除激活的滤镜预设按钮样式。
     */
    function clearActiveFilterPreset() {
      document.querySelectorAll('#filterPresetsContainer .preset-btn').forEach(btn => btn.classList.remove('active-preset'));
    }

    /**
     * 获取锐化矩阵值。
     */
    function getSharpenMatrix(level) {
      if (level === 0) return '';
      // 锐化矩阵的中心值和边缘值会根据 level 变化
      const baseK = 5; // 基础中心值
      const maxKBoost = 8; // 中心值最大增量
      const edgeBase = -0.5; // 基础边缘值
      const maxEdgeBoost = -1.0; // 边缘值最大减量 (负值)

      const kValue = baseK + (maxKBoost * (level - 1) / 9); // 中心值
      const eValue = edgeBase + (maxEdgeBoost * (level - 1) / 9); // 边缘值

      const k = kValue.toFixed(2);
      const e = eValue.toFixed(2);

      // 3x3 锐化卷积核
      return `${e} ${e} ${e} ${e} ${k} ${e} ${e} ${e} ${e}`;
    }

    /**
     * 创建锐化滤镜的 SVG 元素。
     */
    function createSharpenSVGElements() {
      const svgNS = "http://www.w3.org/2000/svg";
      let svgContainer = document.getElementById('sharpen-svg-filters');

      svgContainer.innerHTML = ''; // 清空现有滤镜，防止重复添加

      for (let i = 1; i <= 10; i++) { // 从 1 到 10 级锐化
        const filterId = `sharpen-filter-${i}`;
        const matrixValue = getSharpenMatrix(i);

        const filterElement = document.createElementNS(svgNS, 'filter');
        filterElement.setAttribute('id', filterId);

        const convolveMatrix = document.createElementNS(svgNS, 'feConvolveMatrix');
        convolveMatrix.setAttribute('order', '3'); // 3x3 矩阵
        convolveMatrix.setAttribute('kernelMatrix', matrixValue);
        convolveMatrix.setAttribute('divisor', '1'); // 默认除数，通常用于归一化
        convolveMatrix.setAttribute('bias', '0'); // 默认偏差

        filterElement.appendChild(convolveMatrix);
        svgContainer.appendChild(filterElement);
      }
    }

    /**
     * 设置拖放区域功能。
     */
    function setupDragAndDrop() {
      const uploadArea = document.getElementById('uploadPlaceholder');
      const fileInput = document.getElementById('fileInput');

      // 阻止默认的拖放行为
      ['dragenter', 'dragover', 'dragleave', 'drop'].forEach((eventName) => {
        document.body.addEventListener(eventName, preventDefaults, false); // 全局阻止
        uploadArea.addEventListener(eventName, preventDefaults, false); // 针对上传区域阻止
      });

      function preventDefaults(e) {
        e.preventDefault();
        e.stopPropagation();
      }

      // 拖入/拖出时的样式变化
      ['dragenter', 'dragover'].forEach((eventName) => {
        uploadArea.addEventListener(
          eventName,
          () => {
            uploadArea.classList.add('drag-over');
          },
          false
        );
      });

      ['dragleave', 'drop'].forEach((eventName) => {
        uploadArea.addEventListener(
          eventName,
          () => {
            uploadArea.classList.remove('drag-over');
          },
          false

        );
      });

      // 处理文件拖放
      uploadArea.addEventListener(
        'drop',
        function handleDrop(e) {
            const dt = e.dataTransfer;
            const files = dt.files;
            const videoFiles = [];
            const subtitleFiles = [];

            if (files && files.length) {
                Array.from(files).forEach(file => {
                    const fileName = file.name.toLowerCase();
                    if (fileName.endsWith('.srt') || fileName.endsWith('.vtt')) {
                        subtitleFiles.push(file);
                    } else if (file.type.startsWith('video/') || fileName.endsWith('.mkv')) {
                        videoFiles.push(file);
                    } else {
                        alert(`文件 "${file.name}" 类型不支持。请拖放视频或字幕文件 (.srt, .vtt, .mkv)。`);
                    }
                });

                if (videoFiles.length > 0) {
                    playLocalVideo(videoFiles); // 批量播放视频文件
                }

                if (subtitleFiles.length > 0) {
                    // 如果拖放了多个字幕文件，只处理第一个
                    const file = subtitleFiles[0];
                    const reader = new FileReader();
                    reader.onload = function(event) {
                        parseAndActivateSubtitle(event.target.result);
                        currentSubtitleFileName = file.name;
                        updateSubtitleSelectLabel(file.name);
                    };
                    reader.readAsText(file);
                    if (subtitleFiles.length > 1) {
                        console.warn('检测到多个字幕文件，只加载了第一个。');
                    }
                }
            }
        },
        false
      );
    }

    /**
     * 设置播放器事件监听。
     */
    function setupPlayerEvents() {
        // 这些事件监听器绑定到 nativeVideoPlayer 的 timeupdate 事件，
        // 当 xgplayer 活跃时，其自身的 timeupdate 事件会更新 UI
        // timeupdate 事件不再直接更新进度条和时间显示，而是由 requestAnimationFrame 循环处理
        nativeVideoPlayer.addEventListener('loadedmetadata', function() {
            if (currentPlayingMethod !== 'xgplayer') {
                // 设置进度条最大值和总时长显示
                seekSlider.max = nativeVideoPlayer.duration;
                inVideoSeekSlider.max = nativeVideoPlayer.duration;
                durationDisplay.textContent = formatTime(nativeVideoPlayer.duration);
                inVideoDurationDisplay.textContent = formatTime(nativeVideoPlayer.duration);
                // 初始显示当前时间
                currentTimeDisplay.textContent = formatTime(nativeVideoPlayer.currentTime);
                inVideoCurrentTimeDisplay.textContent = formatTime(nativeVideoPlayer.currentTime);
            }
        });

        nativeVideoPlayer.addEventListener('play', function () {
            if (currentPlayingMethod !== 'xgplayer') {
                updateStatus('playing', `正在播放 (${nativeVideoPlayer.playbackRate}x)`);
                playPauseIcon.className = 'fas fa-pause';
                inVideoPlayPauseIcon.className = 'fas fa-pause';
                uploadPlaceholder.classList.add('hidden');
                videoContainerElement.classList.add('visible');
                resetHideTimer();
                startProgressBarUpdate(); // 启动 requestAnimationFrame 循环
            }
        });

        nativeVideoPlayer.addEventListener('pause', function () {
            if (currentPlayingMethod !== 'xgplayer') { // 仅当原生播放器被使用时
                stopProgressBarUpdate(); // 停止 requestAnimationFrame 循环
                // 仅当不是拖动或键盘快进/快退导致的暂停时，才显示“播放已暂停”
                if (!isSeeking && !isKeyboardSeeking) {
                    updateStatus('stopped', '播放已暂停');
                }
                playPauseIcon.className = 'fas fa-play';
                inVideoPlayPauseIcon.className = 'fas fa-play';
                
                // --- MODIFICATION START ---
                // 根据桌面/移动端区分暂停时的控制条显示逻辑
                if (activePlayer && window.innerWidth > 768) { // PC端
                  // 在PC端暂停时，显示控制条，并启动自动隐藏计时器
                  showControls(); // showControls 会添加 'controls-visible' 并调用 resetHideTimer
                } else { // 移动端 或 activePlayer 不存在时 (保持原有行为，即控制条长期可见)
                  clearTimeout(controlsHideTimeout); // 清除任何现有隐藏计时器
                  inVideoControls.classList.add('controls-visible'); // 强制控制条可见
                }
                // --- MODIFICATION END ---
            }
        });

        nativeVideoPlayer.addEventListener('waiting', function () {
            if (currentPlayingMethod !== 'xgplayer') {
                updateStatus('loading', '正在缓冲...');
            }
        });

        nativeVideoPlayer.addEventListener('ended', handleVideoEnded);

        nativeVideoPlayer.addEventListener('error', handleVideoError);

        // 绑定全局 seeked 事件处理器
        nativeVideoPlayer.addEventListener('seeked', globalSeekedHandler);

        // 进度条拖动事件 (PC端)
        seekSlider.addEventListener('mousedown', handleSeekStart);
        seekSlider.addEventListener('mouseup', handleSeekEnd);
        inVideoSeekSlider.addEventListener('mousedown', handleSeekStart);
        inVideoSeekSlider.addEventListener('mouseup', handleSeekEnd);

        // 进度条拖动事件 (移动端)
        seekSlider.addEventListener('touchstart', handleSeekStart);
        seekSlider.addEventListener('touchend', handleSeekEnd);
        inVideoSeekSlider.addEventListener('touchstart', handleSeekStart);
        inVideoSeekSlider.addEventListener('touchend', handleSeekEnd);

        seekSlider.addEventListener('input', function() {
            // 当用户拖动进度条时，立即更新时间显示，但不影响 requestAnimationFrame 的读取
            currentTimeDisplay.textContent = formatTime(this.value);
            inVideoSeekSlider.value = this.value; // 同步视频内部进度条
            inVideoCurrentTimeDisplay.textContent = formatTime(this.value); // 同步视频内部时间
        });
        inVideoSeekSlider.addEventListener('input', function() {
            inVideoCurrentTimeDisplay.textContent = formatTime(this.value);
            seekSlider.value = this.value; // 同步外部进度条
            currentTimeDisplay.textContent = formatTime(this.value); // 同步外部时间
        });
    }

    /**
     * 全局 seeked 事件处理器。
     */
    function globalSeekedHandler() {
        if (wasPlayingBeforeSeek) {
            activePlayer.play().catch(e => console.error("Error playing after seeked:", e));
        }
        // 根据播放器当前状态更新状态指示器
        if (activePlayer.paused) {
            updateStatus('stopped', '播放已暂停'); // 拖动后暂停，显示暂停状态
        } else {
            updateStatus('playing', `正在播放 (${activePlayer.playbackRate}x)`);
        }
        // 重置标志
        wasPlayingBeforeSeek = false;
        isSeeking = false;
        isKeyboardSeeking = false; // 确保键盘seek标志也重置
        startProgressBarUpdate(); // 重新启动 requestAnimationFrame 循环
    }

    // Common handler for video ended event
    function handleVideoEnded() {
        stopProgressBarUpdate(); // 视频结束时停止 requestAnimationFrame 循环
        updateStatus('stopped', '播放已结束');
        // 检查循环模式
        if (currentLoopMode === 'single') {
            if (activePlayer) { // 确保播放器实例存在
                activePlayer.currentTime = 0;
                activePlayer.play();
                updateStatus('playing', '单曲循环中...');
            }
        } else if (currentLoopMode === 'list') {
            if (playbackHistory.length > 0) {
                let initialIndex = currentPlayingHistoryIndex; // 记录当前播放的索引
                let playedNext = false;

                // 从当前索引的下一个开始遍历，直到找到可播放项或遍历完一圈
                for (let i = 0; i < playbackHistory.length; i++) {
                    const nextIndex = (initialIndex + 1 + i) % playbackHistory.length;
                    const nextItem = playbackHistory[nextIndex];

                    if (!nextItem) {
                        console.warn(`历史记录中索引 ${nextIndex} 的项不存在。`);
                        continue;
                    }

                    // 如果是本地文件且其文件对象已丢失，则跳过
                    if (nextItem.type === 'local' && nextItem.fileObject === null) {
                        console.warn(`列表循环中跳过本地文件 '${nextItem.fileName || nextItem.title}'，因为文件对象已丢失.`);
                        continue;
                    }

                    // 找到了可播放的下一项
                    playFromHistory(nextIndex); // 使用 playFromHistory 来处理对应的视频播放
                    updateStatus('playing', `列表循环中，播放下一项: ${nextItem.title}`);
                    playedNext = true;
                    break;
                }

                if (!playedNext) {
                    // 如果遍历完所有文件都找不到可播放的（例如，所有本地文件都丢失了）
                    if (activePlayer) {
                        activePlayer.currentTime = activePlayer.duration;
                        activePlayer.pause();
                    }
                    updateStatus('stopped', '列表循环结束：所有文件均无法播放或已丢失。');
                    currentPlayingHistoryIndex = -1; // 重置索引，因为循环停止
                }
            } else {
                 if (activePlayer) {
                    activePlayer.currentTime = activePlayer.duration;
                    activePlayer.pause();
                }
            }

        } else if (currentLoopMode === 'shuffle') {
            if (playbackHistory.length > 0) {
                let initialIndex = currentPlayingHistoryIndex;
                let playedNext = false;
                const maxAttempts = playbackHistory.length * 2; // 最多尝试两次遍历列表以找到可播放项

                for (let i = 0; i < maxAttempts; i++) {
                    let nextIndex;
                    if (playbackHistory.length === 1) {
                        nextIndex = 0; // 如果只有一项，强制播放这一项
                    } else {
                        do {
                            nextIndex = Math.floor(Math.random() * playbackHistory.length);
                        } while (playbackHistory.length > 1 && nextIndex === initialIndex); // 确保与当前项不同，除非只有一项
                    }

                    const nextItem = playbackHistory[nextIndex];

                    if (!nextItem) {
                        console.warn(`历史记录中随机索引 ${nextIndex} 的项不存在。`);
                        continue;
                    }

                    // 如果是本地文件且文件对象已丢失，则跳过
                    if (nextItem.type === 'local' && nextItem.fileObject === null) {
                        console.warn(`随机播放中跳过本地文件 '${nextItem.fileName || nextItem.title}'，因为文件对象已丢失.`);
                        if (playbackHistory.length === 1) { // 如果是唯一一项且丢失了，则无法播放
                            break;
                        }
                        continue; // 跳过，重新生成随机索引
                    }

                    // 找到了可播放的下一项
                    playFromHistory(nextIndex); // 使用 playFromHistory 来处理对应的视频播放
                    updateStatus('playing', `随机播放中，播放: ${nextItem.title}`);
                    playedNext = true;
                    break;
                }

                if (!playedNext) {
                    if (activePlayer) {
                         activePlayer.currentTime = activePlayer.duration;
                        activePlayer.pause();
                    }
                    updateStatus('stopped', '随机播放结束：所有文件均无法播放或已丢失。');
                    currentPlayingHistoryIndex = -1; // 重置索引，因为循环停止
                }
            } else {
                if (activePlayer) {
                    activePlayer.currentTime = activePlayer.duration;
                    activePlayer.pause();
                }
            }
        } else {
            // Default behavior (no loop)
            if (activePlayer) {
                activePlayer.currentTime = activePlayer.duration;
                activePlayer.pause(); // 立即暂停
                activePlayer.currentTime = activePlayer.duration; // 精确设置到最后一帧
                seekSlider.value = activePlayer.duration;
                inVideoSeekSlider.value = activePlayer.duration;
                currentTimeDisplay.textContent = formatTime(activePlayer.duration);
                inVideoCurrentTimeDisplay.textContent = formatTime(activePlayer.duration);
            }
            playPauseIcon.className = 'fas fa-play';
            inVideoPlayPauseIcon.className = 'fas fa-play';
        }
    }

    // Common handler for video error event
    function handleVideoError(err) {
        stopProgressBarUpdate(); // 播放错误时停止 requestAnimationFrame 循环
        const error = err || (activePlayer && activePlayer.error); // For xgplayer, error object might be passed directly
        let errorMessage = '未知错误';
        if (error) {
          switch (error.code) {
            case error.MEDIA_ERR_ABORTED:
              errorMessage = '用户终止了播放。';
              break;
            case error.MEDIA_ERR_NETWORK:
              errorMessage = '网络错误导致视频下载失败。';
              break;
            case error.MEDIA_ERR_DECODE:
              errorMessage = '视频解码错误。';
              break;
            case error.MEDIA_ERR_SRC_NOT_SUPPORTED:
              errorMessage = '视频源格式不受支持或文件损坏。';
              break;
            default:
              errorMessage = `错误代码: ${error.code} - ${error.message || error.msg || ''}`; // xgplayer might have 'msg'
              break;
          }
        }
        console.error('播放错误:', error);
        updateStatus('stopped', '播放错误: ' + errorMessage);
        playPauseIcon.className = 'fas fa-play';
        inVideoPlayPauseIcon.className = 'fas fa-play';
        uploadPlaceholder.classList.remove('hidden');
        videoContainerElement.classList.remove('visible');
    }

    /**
     * 拖动或键盘快进/快退开始时的通用处理逻辑。
     */
    function handleSeekStartCommon() {
        wasPlayingBeforeSeek = !activePlayer.paused; // 记录拖动前是否在播放
        activePlayer.pause(); // 暂停播放
        stopProgressBarUpdate(); // 暂停时停止 requestAnimationFrame 循环
        updateStatus('loading', '正在缓冲...'); // 更新状态为缓冲
    }

    function handleSeekStart() {
        isSeeking = true;
        handleSeekStartCommon();
    }

    function handleSeekEnd() {
        // isSeeking = false; // 不在这里重置，由 globalSeekedHandler 重置
        const targetTime = parseFloat(this.value); // 使用触发事件的滑块的值
        activePlayer.currentTime = targetTime;
        // globalSeekedHandler 会在 seeked 事件触发时处理状态更新和播放恢复
    }

    /**
     * 将秒数格式化为 HH:MM:SS 或 MM:SS 格式。
     */
    function formatTime(seconds) {
      const minutes = Math.floor(seconds / 60);
      const remainingSeconds = Math.floor(seconds % 60);
      const hours = Math.floor(minutes / 60);
      const remainingMinutes = Math.floor(minutes % 60); // 修正：这里应该是 minutes % 60

      if (hours > 0) {
        return `${hours.toString().padStart(2, '0')}:${remainingMinutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`;
      } else {
        return `${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`;
      }
    }

    /**
     * 设置外部音量控制。
     */
    function setupVolumeControl() {
      // 初始音量设置应在播放器加载后进行，这里只绑定事件
      // **修复静音 Bug 相关：从本地存储加载音量百分比，或使用默认值 100**
      const storedVolumePercentage = localStorage.getItem('volumePercentage');
      if (storedVolumePercentage !== null) {
          volumeSlider.value = parseInt(storedVolumePercentage, 10);
      } else {
          volumeSlider.value = 100; // HTML default
          // 如果没有保存的音量偏好，则保存 100% 作为默认值
          localStorage.setItem('volumePercentage', '100');
      }

      volumePercentageDisplay.textContent = `${volumeSlider.value}%`; // 初始化音量百分比
      updateMuteButtonIcon(); // 初始更新静音按钮图标

      volumeSlider.addEventListener('input', function () {
        if (!activePlayer) return; // 确保 activePlayer 已定义
        const currentVolume = this.value / 100; // 当前音量 (0.0 - 1.0)
        activePlayer.volume = currentVolume;
        volumePercentageDisplay.textContent = `${this.value}%`; // 更新音量百分比
        inVideoVolumeSlider.value = this.value; // 同步视频内部音量滑块
        inVideoVolumePercentageDisplay.textContent = `${this.value}%`; /// 同步视频内部音量百分比

        // **修复静音 Bug 相关：保存当前音量百分比和非静音音量**
        localStorage.setItem('volumePercentage', this.value); // 保存当前音量百分比
        if (currentVolume > 0) {
            savedVolumeBeforeMute = currentVolume; // 仅当音量非零时更新 savedVolumeBeforeMute
            localStorage.setItem('savedVolumeBeforeMute', savedVolumeBeforeMute.toString());
        }

        if (currentVolume === 0) {
          volumeIcon.className = 'fas fa-volume-off'; // 使用 volume-off 表示完全静音
        } else if (currentVolume < 0.5) {
          volumeIcon.className = 'fas fa-volume-down';
        } else {
          volumeIcon.className = 'fas fa-volume-up';
        }
        updateMuteButtonIcon();
      });

      // 点击音量图标切换静音
      volumeIcon.addEventListener('click', toggleMute);
    }

    /**
     * 设置视频内部音量控制。
     */
    function setupInVideoVolumeControl() {
        inVideoVolumeSlider.value = volumeSlider.value; // 初始化与外部同步
        inVideoVolumePercentageDisplay.textContent = `${inVideoVolumeSlider.value}%`;

        inVideoVolumeSlider.addEventListener('input', function() {
            if (!activePlayer) return; // 确保 activePlayer 已定义
            const currentVolume = this.value / 100; // 当前音量 (0.0 - 1.0)
            activePlayer.volume = currentVolume;
            inVideoVolumePercentageDisplay.textContent = `${this.value}%`;
            volumeSlider.value = this.value; // 同步外部音量滑块
            volumePercentageDisplay.textContent = `${this.value}%`; // 同步外部音量百分比

            // **修复静音 Bug 相关：保存当前音量百分比和非静音音量**
            localStorage.setItem('volumePercentage', this.value); // 保存当前音量百分比
            if (currentVolume > 0) {
                savedVolumeBeforeMute = currentVolume; // 仅当音量非零时更新 savedVolumeBeforeMute
                localStorage.setItem('savedVolumeBeforeMute', savedVolumeBeforeMute.toString());
            }

            if (currentVolume === 0) {
                inVideoVolumeIcon.className = 'fas fa-volume-off';
            } else if (currentVolume < 0.5) {
                inVideoVolumeIcon.className = 'fas fa-volume-down'; // **修复：移除重复代码行**
            } else {
                inVideoVolumeIcon.className = 'fas fa-volume-up'; // **修复：移除重复代码行**
            }
            updateMuteButtonIcon(); // 确保静音按钮图标也同步
        });

        inVideoVolumeIcon.addEventListener('click', toggleMute); // 点击图标静音/取消静音

        // 鼠标滚轮调节音量
        inVideoVolumeSlider.addEventListener('wheel', function(e) {
            e.preventDefault(); // 阻止页面滚动
            let currentVolume = parseInt(this.value);
            if (e.deltaY < 0) { // 向上滚动，增大音量
                currentVolume = Math.min(100, currentVolume + 5);
            } else { // 向下滚动，减小音量
                currentVolume = Math.max(0, currentVolume - 5);
            }
            this.value = currentVolume;
            this.dispatchEvent(new Event('input')); // 触发 input 事件来更新音量和UI
        });
    }

    /**
     * 设置字幕样式控制。
     */
    function setupSubtitleSettings() {
      subtitleSizeSlider.value = currentSubtitleSettings.fontSize;
      subtitleSizeValue.value = currentSubtitleSettings.fontSize;
      subtitleColorPicker.value = currentSubtitleSettings.color;
      applySubtitleSettings();

      subtitleSizeSlider.addEventListener('input', function () {
        subtitleSizeValue.value = this.value;
        currentSubtitleSettings.fontSize = parseInt(this.value);
        applySubtitleSettings();
        saveAllSettings();
      });

      subtitleSizeValue.addEventListener('change', function () {
        let val = parseInt(this.value);
        if (isNaN(val) || val < parseInt(subtitleSizeSlider.min) || val > parseInt(subtitleSizeSlider.max)) {
          val = defaultSubtitleSettings.fontSize;
          this.value = val;
        }
        subtitleSizeSlider.value = val;
        currentSubtitleSettings.fontSize = val;
        applySubtitleSettings();
        saveAllSettings();
      });

      subtitleColorPicker.addEventListener('input', function () {
        currentSubtitleSettings.color = this.value;
        applySubtitleSettings();
        saveAllSettings();
      });
    }

    /**
     * 应用字幕样式。
     */
    function applySubtitleSettings() {
      subtitleDisplay.style.fontSize = `${currentSubtitleSettings.fontSize}px`;
      subtitleDisplay.style.color = currentSubtitleSettings.color;
    }

    /**
     * 保存所有设置到 localStorage。
     */
    function saveAllSettings() {
      localStorage.setItem('subtitleSettings', JSON.stringify(currentSubtitleSettings));
      localStorage.setItem('transformSettings', JSON.stringify(transformSettings));
      localStorage.setItem('filterSettings', JSON.stringify(filterSettings));
      if (activePlayer) { // 只有当 activePlayer 存在时才保存播放速度
        localStorage.setItem('playbackRate', activePlayer.playbackRate || 1.0);
      }
      localStorage.setItem('backgroundSettings', JSON.stringify(backgroundSettings));
      localStorage.setItem('loopMode', currentLoopMode); // 保存循环模式
      // **修复静音 Bug 相关：保存当前音量百分比**
      localStorage.setItem('volumePercentage', volumeSlider.value);
      localStorage.setItem('savedVolumeBeforeMute', savedVolumeBeforeMute.toString());
    }

    /**
     * 从 localStorage 加载所有设置。
     */
    function loadAllSettings() {
      // 加载字幕设置
      const savedSubtitleSettings = localStorage.getItem('subtitleSettings');
      if (savedSubtitleSettings) {
        Object.assign(currentSubtitleSettings, JSON.parse(savedSubtitleSettings));
        setupSubtitleSettings();
      }

      // 加载画面变换设置
      const savedTransformSettings = localStorage.getItem('transformSettings');
      if (savedTransformSettings) {
        Object.assign(transformSettings, JSON.parse(savedTransformSettings));
        zoomSlider.value = transformSettings.zoom;
        zoomValueSpan.textContent = `${transformSettings.zoom}%`;
        applyVideoTransformations(); // 初始应用变换
      }

      // 加载滤镜设置
      const savedFilterSettings = localStorage.getItem('filterSettings');
      if (savedFilterSettings) {
        Object.assign(filterSettings, JSON.parse(savedFilterSettings));
        updateFilterSlidersUI();
        applyVideoFilters(); // 初始应用滤镜
        // 检查是否与预设匹配，并激活相应按钮
        let matchedPreset = false;
        for (const presetKey in filterPresets) {
          const p = filterPresets[presetKey];
          if (p.brightness === filterSettings.brightness &&
              p.contrast === filterSettings.contrast &&
              p.saturation === filterSettings.saturation &&
              p.sharpen === filterSettings.sharpen) {
            const presetButton = document.querySelector(`#filterPresetsContainer .preset-btn[data-preset="${presetKey}"]`);
            if (presetButton) presetButton.classList.add('active-preset');
            matchedPreset = true;
            break;
          }
        }
        if (!matchedPreset) clearActiveFilterPreset();
      }

      // 加载播放速度 (仅更新按钮UI，实际播放速度在视频加载时设置)
      const savedPlaybackRate = localStorage.getItem('playbackRate');
      if (savedPlaybackRate) {
        const speedBtn = document.querySelector(`#speedBtnGroup .btn[data-speed="${savedPlaybackRate}"]`);
        if (speedBtn) {
            speedBtn.classList.add('active-speed-btn');
        }
      } else {
        document.querySelector(`#speedBtnGroup .btn[data-speed="1"]`).classList.add('active-speed-btn');
      }

      // 加载背景设置
      const savedBackgroundSettings = localStorage.getItem('backgroundSettings');
      if (savedBackgroundSettings) {
        Object.assign(backgroundSettings, JSON.parse(savedBackgroundSettings));
      } else {
        // 如果没有保存的设置，则使用默认值
        Object.assign(backgroundSettings, defaultBackgroundSettings);
      }
      backgroundURLInput.value = backgroundSettings.url;
      backgroundBlurSlider.value = backgroundSettings.blur;
      backgroundBlurValueSpan.textContent = `${backgroundSettings.blur}px`;
      applyBackground();

      // 加载循环模式
      currentLoopMode = localStorage.getItem('loopMode') || 'none';
      updateLoopModeButtons();

      // **修复静音 Bug 相关：加载保存的非静音音量值**
      const storedSavedVolumeBeforeMute = localStorage.getItem('savedVolumeBeforeMute');
      if (storedSavedVolumeBeforeMute !== null) {
          savedVolumeBeforeMute = parseFloat(storedSavedVolumeBeforeMute);
      } else {
          savedVolumeBeforeMute = 1.0; // Default
      }
    }

    /**
     * 更新播放状态。
     */
    function updateStatus(status, message) {
      const indicator = document.getElementById('statusIndicator');
      indicator.className = `status-indicator ${status}`;
      indicator.innerHTML = `<i class="fas fa-circle"></i> ${message}`;
    }

    /**
     * 切换播放/暂停状态。
     */
    function togglePlayPause() {
      if (activePlayer) {
        if (activePlayer.paused) {
          activePlayer.play();
        } else {
          activePlayer.pause();
        }
      } else {
        alert('请先加载视频！');
      }
    }

    /**
     * 重新加载视频。
     */
    function reloadVideo() {
        // 如果当前有正在播放的视频且在历史记录中
        if (activePlayer && currentPlayingHistoryIndex !== -1 && playbackHistory[currentPlayingHistoryIndex]) {
            const item = playbackHistory[currentPlayingHistoryIndex];
            if (item.type === 'local') {
                if (item.fileObject) {
                    playFromHistory(currentPlayingHistoryIndex); // 文件对象还在，直接重新播放
                    return;
                } else {
                    alert('本地视频文件已丢失，请重新选择或上传。');
                    document.getElementById('videoURL').value = ''; // 清空URL输入框
                    stopPlaybackInternal(false);
                    return;
                }
            } else { // 如果是远程视频
                play(item.url); // 重新播放远程视频，play() 函数会处理历史记录
                return;
            }
        }

        // 如果没有正在播放的视频或者历史记录不可用，尝试从URL输入框加载
        const inputUrl = document.getElementById('videoURL').value.trim();
        if (inputUrl) {
            play(inputUrl);
        } else {
            alert('没有视频可重新加载。请输入视频URL或点击“上传本地视频”按钮。');
        }
    }

    /**
     * 播放本地视频。
     * @param {File | FileList | Array<File>} fileOrFiles - 单个 File 对象、FileList 或 File 对象数组
     */
    function playLocalVideo(fileOrFiles) {
        let filesArray = [];
        if (fileOrFiles instanceof File) {
            filesArray.push(fileOrFiles);
        } else if (fileOrFiles instanceof FileList || Array.isArray(fileOrFiles)) {
            filesArray = Array.from(fileOrFiles);
        } else {
            console.error("playLocalVideo 接收到无效输入:", fileOrFiles);
            return;
        }

        if (filesArray.length === 0) {
            updateStatus('stopped', '未选择文件');
            return;
        }

        let firstItemToPlay = null;
        let localFilesFound = 0;

        filesArray.forEach(file => {
            const extension = file.name.split('.').pop().toLowerCase();

            if (!supportedFormats.includes(extension)) {
                console.warn(`不支持的视频格式文件已跳过: .${extension} (文件: ${file.name})`);
                return; // 跳过不支持的文件
            }

            localFilesFound++;
            // 为每个本地文件创建一个临时的 Blob URL
            const fileURL = URL.createObjectURL(file);
            const historyItem = {
                // `title` 初始化为默认，如果用户有自定义，后续 `addToHistory` 会保留
                title: `本地文件: ${file.name}`,
                url: fileURL, // Blob URL
                fileName: file.name,
                type: 'local',
                fileObject: file, // 存储 File 对象，但它不会在 localStorage 中持久化
                timestamp: new Date().toISOString(),
            };

            // 添加到历史记录 (addToHistory 会处理是新增还是更新现有)
            addToHistory(historyItem);

            // 标记要首先播放的视频
            if (!firstItemToPlay) {
                firstItemToPlay = historyItem;
            }
        });

        if (firstItemToPlay) {
            // 在更新后的 history 列表中找到第一个要播放的视频的索引
            currentPlayingHistoryIndex = playbackHistory.findIndex(item => item.url === firstItemToPlay.url);
            if (currentPlayingHistoryIndex === -1) {
                // 如果找不到，这可能是个错误情况，暂时默认到第一个
                currentPlayingHistoryIndex = 0;
            }

            // 设置 URL 输入框显示
            document.getElementById('videoURL').value = firstItemToPlay.title;

            // 调用核心播放函数
            playCore(firstItemToPlay.url, firstItemToPlay.fileObject, true, firstItemToPlay.fileName);

            updateStatus('playing', `正在播放: ${firstItemToPlay.fileName}`);

            // 如果上传了多个有效文件，默认将循环模式设置为列表循环
            if (localFilesFound > 1 && currentLoopMode === 'none') {
                setLoopMode('list'); // 自动激活列表循环模式
                updateLoopModeButtons();
            }
        } else if (filesArray.length > 0) { // 有文件但是没有有效的视频文件
            updateStatus('stopped', '未选择有效的本地视频文件。');
            uploadPlaceholder.classList.remove('hidden');
            videoContainerElement.classList.remove('visible');
        }
    }


    /**
     * 播放视频的通用核心函数 (内部调用)。
     * @param {string} url - 视频地址 (可以是网络URL或Blob URL)
     * @param {File} [fileObject=null] - 如果是本地文件，提供对应的 File 对象
     * @param {boolean} [isLocalPlayback=false] - 是否为本地文件播放
     * @param {string} [fileName=null] - 如果是本地文件，提供文件名
     */
    function playCore(url, fileObject = null, isLocalPlayback = false, fileName = null) {
      stopPlaybackInternal(true); // 停止之前的播放并清理旧的 Blob URL

      currentVideoUrl = url;

      updateStatus('loading', '正在加载视频...');

      uploadPlaceholder.classList.add('hidden');
      videoContainerElement.classList.add('visible');

      const extension = getFileExtension(url);
      const isFlv = (extension === 'flv' || url.includes('.flv'));
      const isM3U8 = (extension === 'm3u8' || url.includes('.m3u8'));
      const isMkv = (extension === 'mkv' || url.includes('.mkv')); // 新增：检查是否为MKV

      // **修改：更通用的直播流检测，包含用户提供的huajiao.com域名**
      const isLiveStreamExample = isFlv && (url.includes('live') || url.includes('stream') || url.includes('huajiao.com'));

      // 决定是否使用 xgplayer
      // FLV、特定直播流和 MKV 优先使用 xgplayer
      if (isFlv || isLiveStreamExample || isMkv) {
          currentPlayingMethod = 'xgplayer';
          nativeVideoPlayer.style.display = 'none'; // 隐藏原生 video
          xgplayerContainerElement.style.display = 'block'; // 显示 xgplayer 容器

          try {
              // 销毁之前的 xgplayer 实例（如果有）
              if (xgPlayerInstance) {
                  try {
                      xgPlayerInstance.destroy();
                  } catch (e) {
                      console.warn("Error destroying previous xgplayer instance:", e);
                  }
                  xgPlayerInstance = null;
              }

              const xgplayerConfig = {
                  id: 'xgplayerContainer', // 目标 div ID
                  url: url,
                  playsinline: true,
                  fluid: true, // 响应式尺寸
                  controls: false, // 我们使用自定义控件，禁用 xgplayer 的默认控件
                  autoplay: true, // 让 xgplayer 自动播放
                  // **修改：确保 isLive 参数根据新的检测逻辑设置**
                  isLive: isLiveStreamExample,
                  // IMPORTANT: Ensure volume is explicitly set at instantiation for xgplayer
                  volume: parseFloat(localStorage.getItem('volumePercentage')) / 100 || 1.0, // 新增：在XGPlayer初始化时就设置音量，优先本地存储，否则100%
              };

              // 仅在是 FLV 流或被识别为直播流时才添加 FlvPlayer 插件
              if (isFlv || isLiveStreamExample) {
                  xgplayerConfig.plugins = [FlvPlayer];
              }
              // 对于 MKV，xgplayer 依赖于浏览器对 Media Source Extensions (MSE) 的原生支持，
              // 通常不需要额外的插件，除非是播放非常特殊的编码。

              xgPlayerInstance = new Player(xgplayerConfig);
              activePlayer = xgPlayerInstance; // 设置活跃播放器为 xgplayer 实例

              // Sync the activePlayer's volume to the slider's value AFTER instantiation
              // This is a fallback/sync, the initial volume should already be set by config.
              // We need to ensure the UI volume slider reflects the actual player volume.
              const currentVolumeFromConfig = xgplayerConfig.volume;
              volumeSlider.value = Math.round(currentVolumeFromConfig * 100);
              inVideoVolumeSlider.value = Math.round(currentVolumeFromConfig * 100);
              volumePercentageDisplay.textContent = `${volumeSlider.value}%`;
              inVideoVolumePercentageDisplay.textContent = `${inVideoVolumeSlider.value}%`;

              // 如果播放器非静音启动，则更新 savedVolumeBeforeMute
              if (activePlayer.volume > 0) {
                  savedVolumeBeforeMute = activePlayer.volume;
              }


              // 添加点击事件到xgplayer的video元素，确保MKV视频可以通过点击暂停/播放
              if (xgPlayerInstance && xgPlayerInstance.video) {
              // 不再直接绑定点击事件到xgplayer的video，因为videoContainerElement的事件将统一处理这些点击
              // xgPlayerInstance.video.addEventListener('click', togglePlayPause);
              }

              // 添加键盘事件监听器，确保空格键可以暂停/播放视频，同时避免影响输入框
              // 此处 `xgPlayerInstance` 已经在外部作用域定义，无需 `let xgPlayerInstance = null;`
              document.addEventListener('keydown', (event) => {
              if (event.code === 'Space' && activePlayer === xgPlayerInstance && xgPlayerInstance.video) { // 检查是否是xgplayer且在播放
              const activeElement = document.activeElement;
              if (!['INPUT', 'TEXTAREA'].includes(activeElement.tagName) && !activeElement.isContentEditable) {
              togglePlayPause();
              event.preventDefault();
              }
              }
              });


              // 绑定 xgplayer 的事件到我们的通用 UI 更新函数
              xgPlayerInstance.on('play', () => {
                  updateStatus('playing', `正在播放 (${activePlayer.playbackRate}x)`);
                  playPauseIcon.className = 'fas fa-pause';
                  inVideoPlayPauseIcon.className = 'fas fa-pause';
                  uploadPlaceholder.classList.add('hidden');
                  videoContainerElement.classList.add('visible');
                  resetHideTimer();
                  startProgressBarUpdate(); // 启动 requestAnimationFrame 循环
              });
              xgPlayerInstance.on('pause', () => {
                  stopProgressBarUpdate(); // 停止 requestAnimationFrame 循环
                  // 仅当不是拖动或键盘快进/快退导致的暂停时，才显示“播放已暂停”
                  if (!isSeeking && !isKeyboardSeeking) {
                      updateStatus('stopped', '播放已暂停');
                  }
                  playPauseIcon.className = 'fas fa-play';
                  inVideoPlayPauseIcon.className = 'fas fa-play';

                  // --- MODIFICATION START ---
                  // 根据桌面/移动端区分暂停时的控制条显示逻辑
                  if (activePlayer && window.innerWidth > 768) { // PC端
                    // 在PC端暂停时，显示控制条，并启动自动隐藏计时器
                    showControls(); // showControls 会添加 'controls-visible' 并调用 resetHideTimer
                  } else { // 移动端 或 activePlayer 不存在时 (保持原有行为，即控制条长期可见)
                    clearTimeout(controlsHideTimeout); // 清除任何现有隐藏计时器
                    inVideoControls.classList.add('controls-visible'); // 强制控制条可见
                  }
                  // --- MODIFICATION END ---
              });
              xgPlayerInstance.on('ended', handleVideoEnded);
              xgPlayerInstance.on('error', handleVideoError);
              xgPlayerInstance.on('timeupdate', () => {
                  // timeupdate 事件不再直接更新进度条和时间显示，而是由 requestAnimationFrame 循环处理
                  // 但字幕更新仍然可以在这里进行，或者也可以移到 requestAnimationFrame
                  if (subtitleActive && currentSubtitleTracks.length > 0) {
                      updateSubtitleDisplay(activePlayer.currentTime);
                  } else {
                      subtitleDisplay.textContent = '';
                      subtitleDisplay.style.display = 'none';
                  }
              });
              xgPlayerInstance.on('loadeddata', () => {
                  // 设置进度条最大值和总时长显示
                  seekSlider.max = activePlayer.duration;
                  inVideoSeekSlider.max = activePlayer.duration;
                  durationDisplay.textContent = formatTime(activePlayer.duration);
                  inVideoDurationDisplay.textContent = formatTime(activePlayer.duration);
                  // 初始显示当前时间
                  currentTimeDisplay.textContent = formatTime(activePlayer.currentTime);
                  inVideoCurrentTimeDisplay.textContent = formatTime(activePlayer.currentTime);
              });
              xgPlayerInstance.on('volumechange', () => {
                  // 同步音量滑块和图标
                  volumeSlider.value = Math.round(activePlayer.volume * 100);
                  inVideoVolumeSlider.value = Math.round(activePlayer.volume * 100);
                  volumePercentageDisplay.textContent = `${volumeSlider.value}%`;
                  inVideoVolumePercentageDisplay.textContent = `${inVideoVolumeSlider.value}%`;

                  // **修复静音 Bug 相关：保存当前音量百分比和非静音音量**
                  localStorage.setItem('volumePercentage', volumeSlider.value); // 保存当前音量百分比
                  if (activePlayer.volume > 0) {
                      savedVolumeBeforeMute = activePlayer.volume;
                      localStorage.setItem('savedVolumeBeforeMute', savedVolumeBeforeMute.toString());
                  }

                  if (activePlayer.volume === 0) {
                      volumeIcon.className = 'fas fa-volume-off';
                      inVideoVolumeIcon.className = 'fas fa-volume-off';
                  } else if (activePlayer.volume < 0.5) {
                      volumeIcon.className = 'fas fa-volume-down';
                      inVideoVolumeIcon.className = 'fas fa-volume-down';
                  } else {
                      volumeIcon.className = 'fas fa-volume-up';
                      inVideoVolumeIcon.className = 'fas fa-volume-up';
                  }
                  updateMuteButtonIcon();
              });
              // 绑定 xgplayer 的 seeked 事件到全局处理器
              xgPlayerInstance.on('seeked', globalSeekedHandler);

              // 应用保存的播放速度
              const savedPlaybackRate = localStorage.getItem('playbackRate');
              if (savedPlaybackRate) {
                  activePlayer.playbackRate = parseFloat(savedPlaybackRate);
              } else {
                  activePlayer.playbackRate = 1.0;
              }
              // 更新速度按钮 UI
              document.querySelectorAll('#speedBtnGroup .btn').forEach(btn => btn.classList.remove('active-speed-btn'));
              const activeSpeedBtn = document.querySelector(`#speedBtnGroup .btn[data-speed="${activePlayer.playbackRate}"]`);
              if (activeSpeedBtn) {
                  activeSpeedBtn.classList.add('active-speed-btn');
              }

              // 应用画面变换和滤镜到 xgplayer 内部的 video 元素
              applyVideoTransformations();
              applyVideoFilters();

              xgPlayerInstance.play().catch(e => {
                  console.warn("XGPlayer 自动播放被阻止或播放失败:", e);
                  updateStatus('stopped', '点击播放');
                  playPauseIcon.className = 'fas fa-play';
                  inVideoPlayPauseIcon.className = 'fas fa-play';
              });

          } catch (e) {
              console.error('XGPlayer 初始化失败，尝试原生播放:', e);
              // 如果 xgplayer 失败，则回退到原生播放
              // 注意：原生播放器对 MKV 的支持可能有限
              playWithNativePlayer(url, isM3U8, fileObject);
          }
      } else {
          // 对于 HLS、MP4、WebM 等，使用原生播放器
          playWithNativePlayer(url, isM3U8, fileObject);
      }
    }

    /**
     * 播放在线视频的外部接口。
     * @param {string} url - 视频地址
     */
    function play(url) {
        // 创建临时的历史记录项（或用于查找现有项）
        const tempHistoryItem = {
            title: url, // `title` 初始化为默认，如果用户有自定义，后续 `addToHistory` 会保留
            url: url,
            fileName: null,
            type: 'remote',
            timestamp: new Date().toISOString(),
        };
        // 添加到历史记录。此函数会处理是新增（unshift到顶部）还是更新现有（位置不变） [3][1]
        addToHistory(tempHistoryItem);

        // 找到该视频在更新后的历史记录数组中的实际索引
        currentPlayingHistoryIndex = playbackHistory.findIndex(item => item.type === 'remote' && item.url === url);
        // 如果是新项，它会在索引 0。如果是现有项，它将保留其原始索引。

        // 设置URL输入框
        document.getElementById('videoURL').value = url;

        // 调用核心播放函数
        playCore(url, null, false, null); // 远程 URL 不需要 fileObject 和 fileName
    }


    // 辅助函数，用于处理原生/HLS 播放逻辑
    function playWithNativePlayer(url, isM3U8, fileObject = null) {
        currentPlayingMethod = 'native'; // 默认为原生
        nativeVideoPlayer.style.display = 'block'; // 显示原生 video
        xgplayerContainerElement.style.display = 'none'; // 隐藏 xgplayer 容器
        activePlayer = nativeVideoPlayer; // 设置活跃播放器为原生

        // **修复静音 Bug 相关：设置 activePlayer（原生 video 元素）的初始音量**
        activePlayer.volume = parseFloat(localStorage.getItem('volumePercentage')) / 100 || 1.0;
        // 如果播放器非静音启动，则更新 savedVolumeBeforeMute
        if (activePlayer.volume > 0) {
            savedVolumeBeforeMute = activePlayer.volume;
        }

        // 销毁之前的 HLS.js 实例
        if (hlsInstance) {
            hlsInstance.destroy();
            hlsInstance = null;
        }

        if (url.indexOf('rtmp://') === 0) {
            alert('当前浏览器不支持 RTMP 协议播放，请尝试其他视频格式！');
            updateStatus('stopped', '不支持RTMP协议');
            uploadPlaceholder.classList.remove('hidden');
            videoContainerElement.classList.remove('visible');
            return;
        }

        if (isM3U8) {
            currentPlayingMethod = 'hls';
            if (Hls.isSupported()) {
                // HLS.js 配置优化
                const hlsConfig = {
                    // 启用片段预取以改善启动和寻道时间
                    startFragPrefetch: true,
                    // 尝试预缓冲的最大长度（秒），默认30秒。
                    // 增加此值可能有助于提前缓冲更多数据。
                    maxBufferLength: 60, // 尝试缓冲最多60秒
                    // 允许的最大缓冲长度（秒），默认600秒。
                    // 这是HLS.js将尝试填充的绝对最大值。
                    maxMaxBufferLength: 120, // 允许最多120秒的缓冲
                    // 播放开始/恢复前的最小缓冲长度（秒），默认10秒。
                    // 如果缓冲低于此值，播放将暂停。
                    minBufferLength: 15, // 确保在开始/恢复前至少有15秒的缓冲
                    // fragLoadingMaxRetry: 6, // 片段加载最大重试次数，默认6
                    // fragLoadingRetryDelay: 500, // 片段加载重试延迟，默认500ms
                    // fragLoadingMaxRetryTimeout: 15000, // 片段加载最大重试超时，默认15000ms
                };
                hlsInstance = new Hls(hlsConfig); // 使用优化后的配置
                hlsInstance.loadSource(url);
                hlsInstance.attachMedia(nativeVideoPlayer);
                hlsInstance.on(Hls.Events.MANIFEST_PARSED, function () {
                    nativeVideoPlayer.currentTime = 0.01;
                    nativeVideoPlayer.play().catch((e) => {
                        console.error('HLS播放错误:', e);
                        updateStatus('stopped', '播放错误: ' + e.message);
                        uploadPlaceholder.classList.remove('hidden');
                        videoContainerElement.classList.remove('visible');
                    });
                });
                hlsInstance.on(Hls.Events.ERROR, function (event, data) {
                    console.error('HLS错误:', data);
                    let errorMessage = 'HLS错误: ' + data.details;
                    let statusType = 'loading'; // 默认非致命错误为黄色

                    if (data.fatal) {
                        errorMessage += ' (致命错误)';
                        statusType = 'stopped'; // 致命错误为红色
                        if (data.type === Hls.ErrorTypes.NETWORK_ERROR) {
                            errorMessage += '。请检查网络连接或稍后重试。';
                        } else if (data.type === Hls.ErrorTypes.MEDIA_ERROR) {
                            errorMessage += '。视频流可能已损坏或不受支持。';
                        }
                    }

                    // 明确指定 BUFFER_STALLED_ERROR 为红色，无论是否致命
                    if (data.details === Hls.ErrorDetails.BUFFER_STALLED_ERROR) {
                        errorMessage = 'HLS错误: bufferStalledError';
                        statusType = 'stopped'; // 强制为红色
                    }

                    updateStatus(statusType, errorMessage);

                    if (data.fatal) {
                        // 对于致命错误，销毁实例并尝试恢复或提示用户
                        // 致命错误时必须销毁HLS实例
                        if (hlsInstance) {
                            hlsInstance.destroy();
                            hlsInstance = null;
                        }
                        uploadPlaceholder.classList.remove('hidden');
                        videoContainerElement.classList.remove('visible');
                    }
                });
            } else if (nativeVideoPlayer.canPlayType('application/vnd.apple.mpegurl')) {
                nativeVideoPlayer.src = url;
                nativeVideoPlayer.currentTime = 0.01;
                nativeVideoPlayer.play().catch((e) => {
                    console.error('原生HLS播放错误:', e);
                    updateStatus('stopped', '播放错误: ' + e.message);
                    uploadPlaceholder.classList.remove('hidden');
                    videoContainerElement.classList.remove('visible');
                });
            } else {
                alert('当前浏览器不支持 HLS 视频播放！');
                updateStatus('stopped', '不支持HLS播放');
                uploadPlaceholder.classList.remove('hidden');
                videoContainerElement.classList.remove('visible');
                return;
            }
        } else {
            // 对于其他格式，尝试原生播放
            if (fileObject) { // 如果是本地文件且提供了 File 对象
                nativeVideoPlayer.src = URL.createObjectURL(fileObject);
            } else { // 否则使用提供的 URL
                nativeVideoPlayer.src = url;
            }
            nativeVideoPlayer.currentTime = 0.01;
            nativeVideoPlayer.play().catch((e) => {
                console.error('原生播放错误:', e);
                updateStatus('stopped', '播放失败，尝试其他方式...');

                // 如果原生播放失败，尝试使用 HLS 回退 (例如，对于一些 TS 流)
                if (Hls.isSupported()) {
                    updateStatus('loading', '尝试使用HLS播放...');
                    const hlsConfig = {
                        startFragPrefetch: true,
                        maxBufferLength: 60,
                        maxMaxBufferLength: 120,
                        minBufferLength: 15,
                    };
                    hlsInstance = new Hls(hlsConfig);
                    hlsInstance.loadSource(url);
                    hlsInstance.attachMedia(nativeVideoPlayer);
                    hlsInstance.on(Hls.Events.MANIFEST_PARSED, function () {
                        nativeVideoPlayer.currentTime = 0.01;
                        nativeVideoPlayer.play().catch((e) => {
                            console.error('HLS回退播放错误:', e);
                            updateStatus('stopped', '播放失败');
                            uploadPlaceholder.classList.remove('hidden');
                            videoContainerElement.classList.remove('visible');
                        });
                    });
                    hlsInstance.on(Hls.Events.ERROR, function (event, data) {
                        console.error('HLS回退错误:', data);
                        let errorMessage = 'HLS回退错误: ' + data.details;
                        let statusType = 'loading'; // 默认非致命错误为黄色

                        if (data.fatal) {
                            errorMessage += ' (致命错误)';
                            statusType = 'stopped'; // 致命错误为红色
                            if (data.type === Hls.ErrorTypes.NETWORK_ERROR) {
                                errorMessage += '。请检查网络连接或稍后重试。';
                            } else if (data.type === Hls.ErrorTypes.MEDIA_ERROR) {
                                errorMessage += '。视频流可能已损坏或不受支持。';
                            }
                        }

                        // 明确指定 BUFFER_STALLED_ERROR 为红色，无论是否致命
                        if (data.details === Hls.ErrorDetails.BUFFER_STALLED_ERROR) {
                            errorMessage = 'HLS回退错误: 视频缓冲停滞，请检查网络或尝试重新加载。';
                            statusType = 'stopped'; // 强制为红色
                        }

                        updateStatus(statusType, errorMessage);

                        if (data.fatal) {
                            if (hlsInstance) {
                                hlsInstance.destroy();
                                hlsInstance = null;
                            }
                            uploadPlaceholder.classList.remove('hidden');
                            videoContainerElement.classList.remove('visible');
                        }
                    });
                } else {
                    updateStatus('stopped', '播放失败，浏览器不支持此格式。');
                    uploadPlaceholder.classList.remove('hidden');
                    videoContainerElement.classList.remove('visible');
                }
            });
        }

        // 应用保存的播放速度
        const savedPlaybackRate = localStorage.getItem('playbackRate');
        if (savedPlaybackRate) {
            activePlayer.playbackRate = parseFloat(savedPlaybackRate);
        } else {
            activePlayer.playbackRate = 1.0;
        }
        // 更新速度按钮 UI
        document.querySelectorAll('#speedBtnGroup .btn').forEach(btn => btn.classList.remove('active-speed-btn'));
        const activeSpeedBtn = document.querySelector(`#speedBtnGroup .btn[data-speed="${activePlayer.playbackRate}"]`);
        if (activeSpeedBtn) {
            activeSpeedBtn.classList.add('active-speed-btn');
        }

        // 应用画面变换和滤镜到原生播放器
        applyVideoTransformations();
        applyVideoFilters();
    }

    /**
     * 停止播放内部实现。
     * @param {boolean} keepPlaceholderHidden - 是否保持占位符隐藏。
     */
    function stopPlaybackInternal(keepPlaceholderHidden = false) {
      stopProgressBarUpdate(); // 停止 requestAnimationFrame 循环

      // 停止当前活跃的播放器
      if (activePlayer) {
          activePlayer.pause();
          // 如果当前播放的视频源是 Blob URL，则释放它以避免内存泄漏
          if (activePlayer.src && activePlayer.src.startsWith('blob:')) {
              URL.revokeObjectURL(activePlayer.src);
              console.log('Blob URL revoked:', activePlayer.src); // 调试信息
          }
          // 如果不是 xgplayer，则清空原生 video 的 src
          if (currentPlayingMethod !== 'xgplayer') {
              activePlayer.removeAttribute('src');
              activePlayer.load(); // 触发 load 以清除视频状态
          }
      }

      // 销毁 HLS.js 实例
      if (hlsInstance) {
        hlsInstance.destroy();
        hlsInstance = null;
      }
      // 销毁 xgplayer 实例
      if (xgPlayerInstance) {
          try {
              xgPlayerInstance.destroy();
          } catch (e) {
              console.warn("Error destroying xgplayer instance:", e);
          }
          xgPlayerInstance = null;
      }

      // 重置 UI 元素
      seekSlider.value = 0;
      inVideoSeekSlider.value = 0;
      currentTimeDisplay.textContent = '00:00';
      inVideoCurrentTimeDisplay.textContent = '00:00';
      durationDisplay.textContent = '00:00';
      inVideoDurationDisplay.textContent = '00:00';

      currentVideoUrl = null;
      // 注意：这里不重置 currentPlayingHistoryIndex，因为它表示的是当前播放的项在历史记录中的位置。
      // 只有当明确停止播放器且不再预期任何自动播放时才应重置它。
      // 在循环结束后或用户主动停止时才重置。

      removeSubtitle();

      updateStatus('stopped', '播放器已停止');

      if (!keepPlaceholderHidden) {
        uploadPlaceholder.classList.remove('hidden');
        videoContainerElement.classList.remove('visible');
        document.getElementById('videoURL').value = '';
      }

      // 确保两个播放器容器都隐藏
      nativeVideoPlayer.style.display = 'none';
      xgplayerContainerElement.style.display = 'none';

      // 将活跃播放器重置为原生 video，以备下次播放
      activePlayer = nativeVideoPlayer;
      currentPlayingMethod = 'none';

      playPauseIcon.className = 'fas fa-play';
      inVideoPlayPauseIcon.className = 'fas fa-play';
      clearTimeout(controlsHideTimeout);
      inVideoControls.classList.add('controls-visible');
    }

    /**
     * 停止播放 (外部接口)。
     */
    function stopPlayback() {
      currentPlayingHistoryIndex = -1; // 用户主动停止时重置索引
      stopPlaybackInternal(false);
    }

    /**
     * 获取文件扩展名。
     */
    function getFileExtension(url) {
      const parts = url.split('.');
      if (parts.length > 1) {
        return parts.pop().split(/[#?]/)[0].toLowerCase();
      }
      return '';
    }

    /**
     * Helper: 将时间字符串 (HH:MM:SS,ms 或 HH:MM:SS.ms) 转换为秒数。
     */
    function parseTime(timeStr) {
      const parts = timeStr.split(':');
      const secondsAndMs = parts[parts.length - 1].split(/[,.]/);
      let hours = 0, minutes = 0, seconds = 0, milliseconds = 0;

      if (parts.length === 3) {
          hours = parseInt(parts[0], 10);
          minutes = parseInt(parts[1], 10);
          seconds = parseInt(secondsAndMs[0], 10);
          milliseconds = parseInt(secondsAndMs[1], 10) || 0;
      } else if (parts.length === 2) {
          minutes = parseInt(parts[0], 10);
          seconds = parseInt(secondsAndMs[0], 10);
          milliseconds = parseInt(secondsAndMs[1], 10) || 0;
      }
      return hours * 3600 + minutes * 60 + seconds + milliseconds / 1000;
    }

    /**
     * 解析 SRT 或 VTT 内容为字幕对象数组。
     */
    function parseSrtOrVtt(content) {
      const subtitles = [];
      const lines = content.split(/\r?\n/);
      let i = 0;
      while (i < lines.length) {
        if (!lines[i].trim() || (isNaN(parseInt(lines[i].trim(), 10)) && !lines[i].trim().toUpperCase().startsWith('WEBVTT') && !lines[i].trim().startsWith('NOTE') && !lines[i].trim().startsWith('STYLE') && !lines[i].trim().includes('-->'))) {
          i++;
          continue;
        }

        if (lines[i].trim().toUpperCase() === 'WEBVTT') {
          i++;
          while (i < lines.length && lines[i].trim() === '') i++;
          continue;
        }
        if (lines[i].trim().startsWith('NOTE') || lines[i].trim().startsWith('STYLE')) {
          i++;
          while (i < lines.length && lines[i].trim() === '') i++;
          while (i < lines.length && lines[i].trim() === '') i++;
          continue;
        }

        let cueId = '';
        if (!isNaN(parseInt(lines[i].trim(), 10))) {
          cueId = lines[i].trim();
          i++;
          while (i < lines.length && lines[i].trim() === '') i++;
        }

        let timeLine = '';
        if (i < lines.length && lines[i].includes('-->')) {
          timeLine = lines[i].trim();
          i++;
        } else {
          i++;
          continue;
        }

        let textLines = [];
        while (i < lines.length && lines[i].trim() !== '') {
          textLines.push(lines[i].trim());
          i++;
        }

        const timeParts = timeLine.split(' --> ');
        if (timeParts.length === 2) {
          const start = parseTime(timeParts[0]);
          const end = parseTime(timeParts[1]);
          const text = textLines.join('\n');
          subtitles.push({ start, end, text });
        }
      }
      return subtitles;
    }

    /**
     * 上传字幕文件并加载。
     */
    function uploadSubtitleFile() {
      const input = document.createElement('input');
      input.type = 'file';
      input.accept = '.vtt,.srt';
      input.style.display = 'none';

      input.onchange = function (e) {
        const file = e.target.files[0];
        if (!file) return;

        const reader = new FileReader();
        reader.onload = function (event) {
          const content = event.target.result;
          parseAndActivateSubtitle(content);
          currentSubtitleFileName = file.name;
          updateSubtitleSelectLabel(file.name);
        };
        reader.readAsText(file);
      };

      document.body.appendChild(input);
      input.click();
      document.body.removeChild(input);
    }

    /**
     * 更新字幕选择下拉显示文本（显示文件名，且禁用“上传字幕文件”选项）。
     */
    function updateSubtitleSelectLabel(fileName) {
      const subtitleSelect = document.getElementById('subtitleSelect');
      subtitleSelect.innerHTML = '';

      const noneOption = document.createElement('option');
      noneOption.value = 'none';
      noneOption.textContent = '无字幕';
      subtitleSelect.appendChild(noneOption);

      if (fileName) {
        const fileOption = document.createElement('option');
        fileOption.value = 'uploaded';
        fileOption.textContent = fileName;
        fileOption.selected = true;
        subtitleSelect.appendChild(fileOption);
      } else {
        noneOption.selected = true;
      }
    }

    /**
     * 解析并激活自定义字幕。
     */
    function parseAndActivateSubtitle(content) {
      currentSubtitleTracks = parseSrtOrVtt(content);
      subtitleActive = true;
      subtitleDisplay.style.display = 'block';
      subtitleDisplay.textContent = '';
      if (activePlayer) {
        // 当有字幕时，确保 updateProgressBarFrame 会调用 updateSubtitleDisplay
        // 或者直接在这里调用一次，确保立即显示
        updateSubtitleDisplay(activePlayer.currentTime);
      }
      applySubtitleSettings();
      updateToggleSubtitleButtonIcon();
    }

    /**
     * 根据当前播放时间更新自定义字幕显示。
     */
    function updateSubtitleDisplay(currentTime) {
      let currentCaption = '';

      for (const track of currentSubtitleTracks) {
        if (currentTime >= track.start && currentTime <= track.end) {
          currentCaption = track.text;
          break;
        }
      }
      subtitleDisplay.innerHTML = currentCaption.replace(/\n/g, '<br>');
      subtitleDisplay.style.display = currentCaption ? 'block' : 'none';
    }

    /**
     * 切换字幕显示（仅针对自定义字幕）。
     */
    function toggleSubtitle() {
      if (currentSubtitleTracks.length === 0) {
        alert('没有加载外挂字幕文件。请先上传字幕文件。');
        subtitleActive = false;
        updateToggleSubtitleButtonIcon();
        subtitleDisplay.style.display = 'none';
        return;
      }

      subtitleActive = !subtitleActive;

      // 如果字幕被激活，尝试立即更新其内容
      if (subtitleActive) {
        if (activePlayer) {
            updateSubtitleDisplay(activePlayer.currentTime);
        }
        subtitleDisplay.style.display = 'block';
      } else {
        subtitleDisplay.style.display = 'none';
      }
      updateToggleSubtitleButtonIcon();
    }

    /**
     * 更新显示/隐藏字幕按钮的图标。
     */
    function updateToggleSubtitleButtonIcon() {
      const toggleBtn = document.getElementById('toggleSubtitleBtn');
      if (toggleBtn) {
        const toggleIcon = toggleBtn.querySelector('i');
        if (toggleIcon) {
            // 只有当有实际字幕数据时才显示“切换”图标，否则显示“隐藏”
            if (currentSubtitleTracks.length > 0 && subtitleActive) {
                toggleIcon.className = 'fas fa-eye';
            } else {
                toggleIcon.className = 'fas fa-eye-slash';
            }
        }
      }
    }

    /**
     * 移除所有字幕（自定义）。
     */
    function removeSubtitle() {
      currentSubtitleTracks = [];
      subtitleActive = false;
      currentSubtitleFileName = null;
      subtitleDisplay.textContent = '';
      subtitleDisplay.style.display = 'none';

      // 禁用原生 video 标签的字幕
      for (let i = 0; i < nativeVideoPlayer.textTracks.length; i++) {
        nativeVideoPlayer.textTracks[i].mode = 'disabled';
      }

      updateSubtitleSelectLabel(null);
      updateToggleSubtitleButtonIcon();
    }

    /**
     * Function to determine if a URL is likely a valid video URL.
     */
    function isValidVideoUrl(url) {
      const videoExtensions = ['mp4', 'm3u8', 'flv', 'webm', 'mkv', 'mov', 'avi', 'wmv', '3gp', 'ogg', 'mpg', 'mpeg', 'vob', 'ts',];
      const extension = getFileExtension(url);

      if (url.startsWith('blob:')) {
        return true;
      }

      if (videoExtensions.includes(extension)) {
        return true;
      }

      if (url.includes('.m3u8') || url.includes('.flv')) {
        return true;
      }

      try {
        new URL(url); // 尝试解析为 URL
        return false; // 如果能解析但无后缀，通常不是视频
      } catch (e) {
        return false; // 无法解析则肯定不是有效 URL
      }
    }

    /**
     * 将新的历史记录项添加到历史记录列表。
     * 如果已存在相同的项（URL相同或本地文件名相同），则更新其时间戳但不改变其在列表中的位置。
     * 如果是新项，则添加到列表顶部。
     * @param {object} newItem - 包含 title, url, fileName, type, timestamp, fileObject 的对象。
     */
    function addToHistory(newItem) {
        let existingIndex = -1;

        if (newItem.type === 'local') {
            existingIndex = playbackHistory.findIndex(item => item.type === 'local' && item.fileName === newItem.fileName);
        } else { // Remote URL
            existingIndex = playbackHistory.findIndex(item => item.type === 'remote' && item.url === newItem.url);
        }

        if (existingIndex !== -1) {
            const existingItem = playbackHistory[existingIndex];
            // 计算现有条目的默认标题形式
            const defaultTitleForExistingItem = existingItem.type === 'local' ? `本地文件: ${existingItem.fileName}` : existingItem.url;

            // 只有当现有条目的标题是默认标题时，才用新条目的标题（也是默认标题）覆盖它。
            // 这样可以保留用户自定义的标题。
            if (existingItem.title === defaultTitleForExistingItem) {
                existingItem.title = newItem.title; // 使用 newItem 的默认标题更新
            }
            // else: existingItem.title 是自定义标题，保持不变。

            existingItem.timestamp = newItem.timestamp; // 总是更新时间戳
            if (newItem.type === 'local' && newItem.fileObject) {
                existingItem.fileObject = newItem.fileObject; // 如果是本地文件，总是更新文件对象引用
            }
            // 不改变其在数组中的位置 [1] [2]
        } else {
            // 如果是新项，添加到数组顶部 [3]
            playbackHistory.unshift(newItem);
        }

        // 限制历史记录条目数量
        if (playbackHistory.length > 20) {
            playbackHistory.pop();
        }

        localStorage.setItem('playbackHistory', JSON.stringify(playbackHistory, (key, value) => {
            // 在保存到 localStorage 时，移除 File 对象，因为它不可序列化
            if (key === 'fileObject') {
                return undefined;
            }
            return value;
        }));
        renderHistory(); // 重新渲染历史记录列表
    }

    /**
     * Helper function to create event handlers for input.
     */
    function createInputHandlers(index) {
      const historyItem = document.getElementById(`historyItem_${index}`);
      const editInput = historyItem.querySelector('.history-title-edit');

      const blurHandler = (event) => {
        if (currentlyEditingIndex === index) {
            // 确保失去焦点不是由于点击保存按钮
            if (!event.relatedTarget || !event.relatedTarget.closest('.edit-save-btn')) {
                saveEditMode(currentlyEditingIndex); // 确保传递正确的索引
            }
        }
      };

      const keypressHandler = (event) => {
        if (event.key === 'Enter') {
          saveEditMode(index);
          event.preventDefault();
        }
      };

      return { blurHandler, keypressHandler };
    }

    /**
     * 启动编辑模式。
     */
    function startEditMode(index) {
      if (currentlyEditingIndex !== -1 && currentlyEditingIndex !== index) {
        saveEditMode(currentlyEditingIndex);
      }

      const historyItem = document.getElementById(`historyItem_${index}`);
      if (!historyItem) return;

      const displaySpan = historyItem.querySelector('.history-title-display');
      const editInput = historyItem.querySelector('.history-title-edit');
      const editSaveBtn = historyItem.querySelector('.edit-save-btn');
      const editSaveIcon = editSaveBtn.querySelector('i');
      const editSaveLabel = editSaveBtn.querySelector('.button-label');

      displaySpan.style.display = 'none';
      editInput.style.display = 'inline-block';
      editInput.value = displaySpan.textContent;
      editInput.focus();
      editInput.select();

      editSaveBtn.setAttribute('data-action', 'save');
      editSaveIcon.className = 'fas fa-check';
      editSaveLabel.textContent = '保存';

      const handlers = createInputHandlers(index);
      editInput.addEventListener('blur', handlers.blurHandler);
      editInput.addEventListener('keypress', handlers.keypressHandler);
      // 使用 Map 存储监听器引用，以便正确移除
      if (!window._inputEventListenersMap) window._inputEventListenersMap = new Map();
      window._inputEventListenersMap.set(index, handlers);

      currentlyEditingIndex = index;
    }

    /**
     * 保存编辑模式。
     */
    function saveEditMode(index) {
      if (currentlyEditingIndex !== index) return;

      const historyItem = document.getElementById(`historyItem_${index}`);
      if (!historyItem) return;

      const displaySpan = historyItem.querySelector('.history-title-display');
      const editInput = historyItem.querySelector('.history-title-edit');
      const editSaveBtn = historyItem.querySelector('.edit-save-btn');
      const editSaveIcon = editSaveBtn.querySelector('i');
      const editSaveLabel = editSaveBtn.querySelector('.button-label');

      const newTitle = editInput.value.trim();

      if (newTitle === '') {
        editInput.value = playbackHistory[index].title;
      } else {
        playbackHistory[index].title = newTitle;
        localStorage.setItem('playbackHistory', JSON.stringify(playbackHistory, (key, value) => {
            if (key === 'fileObject') { return undefined; } // 确保 File 对象不被序列化
            return value;
        }));
      }
      displaySpan.textContent = playbackHistory[index].title;

      displaySpan.style.display = 'inline-block';
      editInput.style.display = 'none';

      editSaveBtn.setAttribute('data-action', 'edit');
      editSaveIcon.className = 'fas fa-edit';
      editSaveLabel.textContent = '备注';

      const handlers = window._inputEventListenersMap.get(index);
      if (handlers) {
        editInput.removeEventListener('blur', handlers.blurHandler);
        editInput.removeEventListener('keypress', handlers.keypressHandler);
        window._inputEventListenersMap.delete(index);
      }

      currentlyEditingIndex = -1;
    }

    /**
     * 渲染历史记录。
     */
    function renderHistory() {
      const historyList = document.getElementById('historyList');

      if (currentlyEditingIndex !== -1) {
        saveEditMode(currentlyEditingIndex);
      }

      if (window._inputEventListenersMap) {
        window._inputEventListenersMap.clear();
      }
      currentlyEditingIndex = -1;

      if (playbackHistory.length === 0) {
        historyList.innerHTML = '<div class="empty-history">暂无播放历史</div>';
        return;
      }

      historyList.innerHTML = '';

      playbackHistory.forEach((item, index) => {
        const historyItem = document.createElement('div');
        historyItem.className = 'history-item';
        historyItem.id = `historyItem_${index}`;

        let formatTagHtml = '';
        if (isValidVideoUrl(item.url) || item.type === 'local') { // 本地文件也应显示格式标签
          let format = '未知';
          if (item.type === 'local') {
            format = '本地';
          } else {
            const ext = getFileExtension(item.url);
            if (ext) {
              format = ext.toUpperCase();
            } else if (item.url.includes('.m3u8')) {
              format = 'M3U8';
            } else if (item.url.includes('.flv')) {
              format = 'FLV';
            }
          }
          formatTagHtml = `<div class="format-tag">${format}</div>`;
        }

        historyItem.innerHTML = `
          <div class="title-wrapper">
            <span class="history-title-display">${item.title}</span>
            <input type="text" class="history-title-edit" value="${item.title}" style="display:none;" />
          </div>
          ${formatTagHtml}
          <div class="actions">
            <button class="btn btn-icon" onclick="playFromHistory(${index})" aria-label="播放">
              <i class="fas fa-play"></i>
              <span class="button-label">播放</span>
            </button>
            <button class="btn btn-icon edit-save-btn" data-index="${index}" data-action="edit" aria-label="备注">
              <i class="fas fa-edit"></i>
              <span class="button-label">备注</span>
            </button>
            <button class="btn btn-icon" onclick="removeHistoryItem(${index})" aria-label="删除">
              <i class="fas fa-trash"></i>
              <span class="button-label">删除</span>
            </button>
          </div>
        `;
        historyList.appendChild(historyItem);
      });
    }

    /**
     * 从历史记录播放。
     */
    function playFromHistory(index) {
      const item = playbackHistory[index];
      if (!item) return;

      currentPlayingHistoryIndex = index; // 设置当前播放的历史记录索引

      if (item.type === 'local') {
        // 检查原始的 File 对象是否仍然可用 (仅在同一会话中)
        if (item.fileObject) {
            document.getElementById('videoURL').value = item.title; // 更新 URL 输入框显示
            playCore(item.url, item.fileObject, true, item.fileName); // 播放本地文件
        } else {
            // 如果 File 对象丢失 (例如页面刷新后)，则无法播放
            // 在循环模式下，我们已经处理了跳过逻辑，这里只针对用户在历史记录中点击的情况进行提示
            alert('本地视频文件已丢失。请重新上传该文件以播放。');
            document.getElementById('videoURL').value = ''; // 清空URL输入框
            stopPlaybackInternal(false); // 停止并清理播放器
            // 重新渲染历史记录，确保无法播放的本地文件旁边有提示或可区分
            renderHistory(); // 重新渲染历史记录，显示当前状态
        }
      } else {
        document.getElementById('videoURL').value = item.url;
        playCore(item.url, null, false, null); // 播放远程 URL
      }
    }

    /**
     * 删除历史记录项。
     */
    function removeHistoryItem(index) {
      playbackHistory.splice(index, 1);
      localStorage.setItem('playbackHistory', JSON.stringify(playbackHistory, (key, value) => {
          if (key === 'fileObject') { return undefined; }
          return value;
      }));
      renderHistory();
      // 如果删除的是当前正在播放的项，重置索引
      if (currentPlayingHistoryIndex === index) {
          currentPlayingHistoryIndex = -1;
      } else if (currentPlayingHistoryIndex > index) {
          currentPlayingHistoryIndex--; // 调整后续索引
      }
    }

    /**
     * 清空历史记录。
     */
    function clearHistory() {
      if (playbackHistory.length === 0) return;

      if (confirm('确定要清空所有播放历史吗？')) {
        playbackHistory = [];
        localStorage.removeItem('playbackHistory');
        renderHistory();
        currentPlayingHistoryIndex = -1; // 清空历史记录后重置索引
      }
    }

    /**
     * 判断是否为移动设备。
     */
    function isMobileDevice() {
      return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
    }

    /**
     * 切换全屏。
     */
    function toggleFullscreen() {
        if (!activePlayer) return;

        if (document.fullscreenElement) {
            // 当前处于全屏模式，退出全屏
            if (currentPlayingMethod === 'xgplayer' && xgPlayerInstance && xgPlayerInstance.fullscreen) {
                xgPlayerInstance.fullscreen.exit();
            } else {
                if (document.exitFullscreen) {
                    document.exitFullscreen();
                } else if (document.mozCancelFullScreen) {
                    document.mozCancelFullScreen();
                } else if (document.webkitExitFullscreen) {
                    document.webkitExitFullscreen();
                } else if (document.msExitFullscreen) {
                    document.msRequestFullscreen(); // MSFullscreen 应该用 RequestFullscreen
                }
            }
            // 退出全屏时，如果是在移动设备上，解锁屏幕方向
            if (isMobileDevice() && screen.orientation && screen.orientation.unlock) {
                screen.orientation.unlock();
                console.log('Screen orientation unlocked.');
            }
        } else {
            // 不处于全屏模式，请求全屏
            if (currentPlayingMethod === 'xgplayer' && xgPlayerInstance && xgPlayerInstance.fullscreen) {
                xgPlayerInstance.fullscreen.request();
            } else {
                if (videoContainerElement.requestFullscreen) {
                    videoContainerElement.requestFullscreen();
                } else if (videoContainerElement.mozRequestFullScreen) {
                    videoContainerElement.mozRequestFullScreen();
                } else if (videoContainerElement.webkitRequestFullscreen) {
                    videoContainerElement.webkitRequestFullscreen();
                } else if (videoContainerElement.msRequestFullscreen) {
                    videoContainerElement.msRequestFullscreen();
                }
            }
            // 进入全屏时，如果是在移动设备上，尝试锁定屏幕方向为横屏
            if (isMobileDevice() && screen.orientation && screen.orientation.lock) {
                screen.orientation.lock('landscape').then(() => {
                    console.log('Screen orientation locked to landscape.');
                }).catch((err) => {
                    console.warn('Failed to lock screen orientation:', err);
                });
            }
        }
    }

    /**
     * 更改播放速度。
     */
    function changeSpeed(speed, buttonElement) {
      if (activePlayer) {
        activePlayer.playbackRate = speed;
        document.querySelectorAll('#speedBtnGroup .btn').forEach(btn => btn.classList.remove('active-speed-btn'));
        if (buttonElement) {
          buttonElement.classList.add('active-speed-btn');
        }
        if (!activePlayer.paused) {
          updateStatus('playing', `正在播放 (${speed}x)`);
        }
        saveAllSettings();
      }
    }

    /**
     * 切换静音。
     */
    function toggleMute() {
      if (!activePlayer) return;

      // 如果当前音量大于 0 (未静音)，则将当前音量保存为下次取消静音的音量
      // 注意：savedVolumeBeforeMute 已经在 slider 的 input 事件中更新
      // 这里只需要在静音时，将 activePlayer.volume 设置为 0，并将 UI 更新到 0
      // 在取消静音时，将 activePlayer.volume 设置为 savedVolumeBeforeMute
      if (activePlayer.volume > 0) {
        activePlayer.volume = 0;
        volumeSlider.value = 0;
        inVideoVolumeSlider.value = 0;
      } else {
        // 如果当前音量为 0 (已静音)，则恢复到上次的非静音音量
        const targetVolume = savedVolumeBeforeMute > 0 ? savedVolumeBeforeMute : 1.0; // 如果 savedVolumeBeforeMute 也是0，默认恢复到 1.0
        activePlayer.volume = targetVolume;
        volumeSlider.value = Math.round(targetVolume * 100);
        inVideoVolumeSlider.value = Math.round(targetVolume * 100);
      }

      // **修复静音 Bug 相关：确保静音/取消静音操作后音量百分比被保存**
      localStorage.setItem('volumePercentage', volumeSlider.value); // 保存当前音量百分比

      volumePercentageDisplay.textContent = `${volumeSlider.value}%`;
      inVideoVolumePercentageDisplay.textContent = `${inVideoVolumeSlider.value}%`;

      // 根据当前音量更新音量图标
      if (activePlayer.volume === 0) {
        volumeIcon.className = 'fas fa-volume-off';
        inVideoVolumeIcon.className = 'fas fa-volume-off';
      } else if (activePlayer.volume < 0.5) {
        volumeIcon.className = 'fas fa-volume-down';
        inVideoVolumeIcon.className = 'fas fa-volume-down';
      } else {
        volumeIcon.className = 'fas fa-volume-up';
        inVideoVolumeIcon.className = 'fas fa-volume-up';
      }

      updateMuteButtonIcon();
    }

    /**
     * 更新静音按钮的图标。
     */
    function updateMuteButtonIcon() {
      const muteButton = document.getElementById('muteButton');
      if (muteButton && muteButtonIcon && activePlayer) {
        if (activePlayer.volume === 0) {
          muteButtonIcon.className = 'fas fa-volume-off'; // 使用 volume-off 表示静音
          muteButton.setAttribute('aria-label', '取消静音');
        } else {
          muteButtonIcon.className = 'fas fa-volume-up'; // 使用 volume-up 表示非静音
          muteButton.setAttribute('aria-label', '静音');
        }
      }
    }

    /**
     * 主题切换功能。
     */
    document.getElementById('themeToggle').addEventListener('click', function () {
      document.body.classList.toggle('dark-mode');
      localStorage.setItem('darkMode', document.body.classList.contains('dark-mode'));

      const icon = this.querySelector('i');
      if (document.body.classList.contains('dark-mode')) {
        icon.className = 'fas fa-sun';
      } else {
        icon.className = 'fas fa-moon';
      }
    });

    /**
     * 加载主题设置。
     */
    function loadTheme() {
      const darkMode = localStorage.getItem('darkMode') === 'true';
      const themeToggle = document.getElementById('themeToggle');
      const icon = themeToggle.querySelector('i');

      if (darkMode) {
        document.body.classList.add('dark-mode');
        icon.className = 'fas fa-sun';
      } else {
        icon.className = 'fas fa-moon';
      }
    }

    /**
     * 处理键盘事件 (空格键播放/暂停，左右方向键快进/快退)。
     */
    function handleKeyDown(event) {
        // 检查焦点是否在输入框或文本区域
        const isInputFocused = event.target.tagName === 'INPUT' || event.target.tagName === 'TEXTAREA';

        if (activePlayer && !isInputFocused) { // 确保有活跃播放器且焦点不在输入框
            if (event.key === ' ') {
                event.preventDefault(); // 阻止默认的空格键行为 (如页面滚动)
                togglePlayPause();
            } else if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') {
                event.preventDefault(); // 阻止默认的滚动行为

                if (!isKeyboardSeeking) {
                    isKeyboardSeeking = true;
                    handleSeekStartCommon(); // 调用通用开始seek逻辑
                    keyboardSeekCurrentTime = activePlayer.currentTime; // 初始化预览时间为当前播放时间
                }

                // 清除之前的定时器，实现防抖
                clearTimeout(keyboardSeekTimeout);

                const seekAmount = (event.key === 'ArrowRight' ? 5 : -5); // 每次快进/快退 5 秒
                // 更新预览时间，并确保不超出视频范围
                const duration = isNaN(activePlayer.duration) || activePlayer.duration === Infinity ? 0 : activePlayer.duration;
                keyboardSeekCurrentTime = Math.max(0, Math.min(duration, keyboardSeekCurrentTime + seekAmount));

                // 更新UI显示预览时间
                seekSlider.value = keyboardSeekCurrentTime;
                inVideoSeekSlider.value = keyboardSeekCurrentTime;
                currentTimeDisplay.textContent = formatTime(keyboardSeekCurrentTime);
                inVideoCurrentTimeDisplay.textContent = formatTime(keyboardSeekCurrentTime);

                // 设置定时器，在短暂停顿后才实际执行seek操作
                keyboardSeekTimeout = setTimeout(() => {
                    activePlayer.currentTime = keyboardSeekCurrentTime;
                    // isKeyboardSeeking = false; // 不在这里重置，由 globalSeekedHandler 重置
                    // 实际seek完成后，globalSeekedHandler 会处理状态更新和播放恢复
                }, 200); // 200ms 内没有新的按键事件，则执行seek
            }
        }
    }

    /**
     * 设置循环模式。
     * @param {string} mode - 'none', 'single', 'list', 'shuffle'
     */
    function setLoopMode(mode) {
        if (currentLoopMode === mode) {
            currentLoopMode = 'none'; // 再次点击取消
        } else {
            currentLoopMode = mode;
        }
        localStorage.setItem('loopMode', currentLoopMode);
        updateLoopModeButtons();

        // 提示用户当前循环模式
        let message = '';
        switch(currentLoopMode) {
            case 'single':
                message = '已开启单曲循环';
                break;
            case 'list':
                message = '已开启列表循环';
                break;
            case 'shuffle':
                message = '已开启随机播放';
                break;
            default:
                message = '已关闭循环模式';
                break;
        }
        updateStatus('stopped', message); // 使用停止状态的样式显示提示
    }

    /**
     * 更新循环模式按钮的激活状态。
     */
    function updateLoopModeButtons() {
        document.querySelectorAll('.history-loop-controls .btn').forEach(btn => {
            if (btn.dataset.loopMode === currentLoopMode) {
                btn.classList.add('active-loop-mode');
            } else {
                btn.classList.remove('active-loop-mode');
            }
        });
    }

    // --- 新增：字节格式化辅助函数 ---
    function formatBytes(bytes, decimals = 2) {
        if (bytes === 0) return '0 Bytes';
        const k = 1024;
        const dm = decimals < 0 ? 0 : decimals;
        const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
        const i = Math.floor(Math.log(bytes) / Math.log(k));
        return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
    }

    // --- 新的下载功能 (参考用户提供代码) ---
    async function downloadVideo() {
      const url = currentVideoUrl; // 获取当前播放视频的 URL

      if (!url || url === 'about:blank') { // 检查是否有 URL 且不是 about:blank
        alert('没有正在播放的视频可以下载。');
        return;
      }

      // 处理本地文件
      if (url.startsWith('blob:')) {
        alert('当前正在播放的是本地视频，无需下载。');
        return;
      }

      updateStatus('loading', '正在准备下载...');

      try {
        const extension = getFileExtension(url);
        let filename = `video_${Date.now()}`; // 默认文件名

        // 尝试从 URL 中获取更好的文件名
        try {
            const urlObj = new URL(url);
            const pathSegments = urlObj.pathname.split('/');
            const lastSegment = pathSegments[pathSegments.length - 1];
            if (lastSegment && lastSegment.includes('.')) {
                filename = lastSegment.split('?')[0].split('#')[0];
            } else if (extension) {
                filename += `.${extension}`;
            }
        } catch (e) {
            console.warn("无法解析 URL 以获取文件名，使用默认值。", e);
            if (extension) {
                filename += `.${extension}`;
            }
        }

        if (extension === 'm3u8' || url.includes('.m3u8')) {
          // HLS (M3U8) 下载
          await downloadHLS(url, filename);
        } else if (extension === 'flv' || url.includes('.flv')) {
          // FLV 下载 (假设是直接的 FLV 文件)
          await downloadDirect(url, filename);
        } else {
          // 其他格式 (MP4, WebM 等) 直接下载
          await downloadDirect(url, filename);
        }
        updateStatus('playing', '下载准备完成，浏览器将开始下载。');
      } catch (error) {
        console.error('下载失败:', error);
        updateStatus('stopped', `下载失败: ${error.message || '未知错误'}`);
        alert(`下载失败: ${error.message || '未知错误'}\n请检查控制台获取更多信息。`);
      }
    }

    // 直接文件下载辅助函数
    async function downloadDirect(url, filename) {
      const a = document.createElement('a');
      a.href = url;
      a.download = filename; // Suggested filename
      document.body.appendChild(a);
      a.click(); // Trigger the download

      // For blob URLs, revoke the URL after a short delay to allow download to start
      // For direct URLs, the browser handles the lifecycle, no need to revoke
      if (url.startsWith('blob:')) {
          setTimeout(() => {
              URL.revokeObjectURL(url); // Clean up the object URL
              document.body.removeChild(a); // Remove the anchor element
          }, 5000); // Give it 5 seconds to initiate download on mobile
      } else {
          // For direct URLs, remove the anchor element immediately after click
          // The browser will handle the download process independently
          document.body.removeChild(a);
      }
    }

    // HLS (M3U8) 下载辅助函数
    async function downloadHLS(m3u8Url, baseFilename) {
      updateStatus('loading', '正在下载M3U8播放列表...');
      const response = await fetch(m3u8Url);
      if (!response.ok) {
        throw new Error(`Failed to fetch M3U8 manifest: ${response.statusText}`);
      }
      const manifestText = await response.text();

      const segmentUrls = [];
      const baseUrl = m3u8Url.substring(0, m3u8Url.lastIndexOf('/') + 1); // Correctly calculate baseUrl

      const lines = manifestText.split('\n'); // Split manifest into lines
      for (const line of lines) {
        if (line.startsWith('#') || line.trim() === '') {
          continue; // Skip comments and empty lines
        }
        // Handle master playlist (if it points to other .m3u8 files)
        if (line.endsWith('.m3u8')) {
            const variantUrl = new URL(line, baseUrl).href; // Resolve relative URL
            console.log(`Found variant M3U8: ${variantUrl}. Attempting to download it.`);
            // Recursively call for variant. This will download the first variant found.
            return downloadHLS(variantUrl, baseFilename);
        }
        // Assume it's a segment URL
        const segmentUrl = new URL(line, baseUrl).href; // Resolve relative URL
        segmentUrls.push(segmentUrl);
      }

      if (segmentUrls.length === 0) {
        throw new Error('No video segments found in M3u8 manifest.');
      }

      let downloadedSegmentsCount = 0;
      let downloadedTotalBytes = 0;
      const totalSegments = segmentUrls.length;

      // Create an array of Promises for concurrent download of all segments
      const segmentPromises = segmentUrls.map(async (segmentUrl, index) => {
          try {
              const segmentResponse = await fetch(segmentUrl);
              if (!segmentResponse.ok) {
                  throw new Error(`Failed to fetch segment ${index + 1}: ${segmentResponse.statusText}`);
              }
              const buffer = await segmentResponse.arrayBuffer();

              // Update progress (this part will be called as each Promise resolves)
              downloadedSegmentsCount++; // Increment completed segment count
              downloadedTotalBytes += buffer.byteLength; // Accumulate downloaded bytes

              // Update download status in real-time
              updateStatus('loading', `正在下载片段 (${downloadedSegmentsCount}/${totalSegments}) - ${formatBytes(downloadedTotalBytes)}`);

              return new Uint8Array(buffer);
          } catch (error) {
              console.error(`Error fetching segment ${index + 1}:`, error);
              // Re-throw the error to ensure Promise.all rejects if any segment fails
              throw error;
          }
      });

      updateStatus('loading', `正在下载片段 (0/${totalSegments}) - 0 Bytes`); // Initial display

      // Wait for all segments to download
      const segmentData = await Promise.all(segmentPromises);

      updateStatus('loading', '正在合并视频片段...');
      // Concatenate all ArrayBuffers
      const totalLength = segmentData.reduce((acc, val) => acc + val.length, 0);
      const concatenatedBuffer = new Uint8Array(totalLength);
      let offset = 0;
      for (const segment of segmentData) {
        concatenatedBuffer.set(segment, offset);
        offset += segment.length;
      }

      // Determine MIME type. For .ts segments, it's usually video/mp2t.
      const blob = new Blob([concatenatedBuffer], { type: 'video/mp2t' });

      // Use msSaveBlob for IE/Edge if available (though less common on mobile now)
      if (navigator.msSaveBlob) {
          navigator.msSaveBlob(blob, `${baseFilename.replace(/\.m3u8$/, '')}.ts`);
          updateStatus('playing', '下载已开始 (IE/Edge)');
      } else {
          const downloadLink = document.createElement('a');
          downloadLink.href = URL.createObjectURL(blob);
          // Suggest .ts extension for concatenated HLS, remove .m3u8 from original filename
          downloadLink.download = `${baseFilename.replace(/\.m3u8$/, '')}.ts`;
          document.body.appendChild(downloadLink);
          downloadLink.click(); // Trigger the download

          // Clean up the object URL and the anchor element after a delay
          setTimeout(() => {
              URL.revokeObjectURL(downloadLink.href); // Clean up the object URL
              document.body.removeChild(downloadLink); // Remove the anchor element
          }, 5000); // Give it 5 seconds to initiate download on mobile
      }
    }
  </script>
</body>
</html>
